Compare commits
No commits in common. "3665351e1222a9e53ccf43da5acefc99ace0f164" and "244f222eb0b42f96eb59c88d840555580bb1d712" have entirely different histories.
3665351e12
...
244f222eb0
3
lang-trials/rust-benchmark/.gitignore
vendored
3
lang-trials/rust-benchmark/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
target/*
|
|
||||||
dist/*
|
|
||||||
Cargo.lock
|
|
@ -1,35 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "sycamore-trial"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["Aaron"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["console_error_panic_hook"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
nalgebra = "0.33.0"
|
|
||||||
sycamore = "0.9.0-beta.2"
|
|
||||||
typenum = "1.17.0"
|
|
||||||
|
|
||||||
# The `console_error_panic_hook` crate provides better debugging of panics by
|
|
||||||
# logging them with `console.error`. This is great for development, but requires
|
|
||||||
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
|
|
||||||
# code size when deploying.
|
|
||||||
console_error_panic_hook = { version = "0.1.7", optional = true }
|
|
||||||
|
|
||||||
[dependencies.web-sys]
|
|
||||||
version = "0.3.69"
|
|
||||||
features = [
|
|
||||||
'CanvasRenderingContext2d',
|
|
||||||
'HtmlCanvasElement',
|
|
||||||
'Window',
|
|
||||||
'Performance'
|
|
||||||
]
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
wasm-bindgen-test = "0.3.34"
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
opt-level = "s" # optimize for small code size
|
|
||||||
debug = true # include debug symbols
|
|
@ -1,9 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<title>The circular law</title>
|
|
||||||
<link data-trunk rel="css" href="main.css"/>
|
|
||||||
</head>
|
|
||||||
<body></body>
|
|
||||||
</html>
|
|
@ -1,23 +0,0 @@
|
|||||||
body {
|
|
||||||
margin-left: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
color: #fcfcfc;
|
|
||||||
background-color: #202020;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
float: left;
|
|
||||||
background-color: #020202;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
in profiling, most time is being spent in the `reflect` method:
|
|
||||||
|
|
||||||
f64:
|
|
||||||
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::h7899977a4ba0b1d3
|
|
||||||
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::hc337c3cb6e3b4061
|
|
||||||
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect_rows::h43d0f6838d0c2833
|
|
||||||
|
|
||||||
f32:
|
|
||||||
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::h0e8ec322f198f847
|
|
||||||
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect::h9928bdd5e72743ea
|
|
||||||
sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection<T,D,S>::reflect_rows::h49f571fd8fc9b0f2
|
|
||||||
|
|
||||||
in one test, we spent 4000 ms in "WASM closure", but the enveloping "VoidFunction" takes 1300 ms longer. in another test, though, there's no overhang; the 7000 ms we spent in `rand_eigval_series` accounts for basically the entire load time, and matches the clock timing
|
|
@ -1,164 +0,0 @@
|
|||||||
use nalgebra::{*, allocator::Allocator};
|
|
||||||
use std::f64::consts::{PI, E};
|
|
||||||
/*use std::ops::Sub;*/
|
|
||||||
/*use typenum::{B1, UInt, UTerm};*/
|
|
||||||
|
|
||||||
/* dynamic matrices */
|
|
||||||
pub fn rand_eigval_series<N>(time_res: usize) -> Vec<OVector<Complex<f64>, Dyn>>
|
|
||||||
where
|
|
||||||
N: ToTypenum + DimName + DimSub<U1>,
|
|
||||||
DefaultAllocator:
|
|
||||||
Allocator<N> +
|
|
||||||
Allocator<N, N> +
|
|
||||||
Allocator<<N as DimSub<U1>>::Output> +
|
|
||||||
Allocator<N, <N as DimSub<U1>>::Output>
|
|
||||||
{
|
|
||||||
// initialize the random matrix
|
|
||||||
let dim = N::try_to_usize().unwrap();
|
|
||||||
let mut rand_mat = DMatrix::<f64>::from_fn(dim, dim, |j, k| {
|
|
||||||
let n = j*dim + k;
|
|
||||||
E*((n*n) as f64) % 2.0 - 1.0
|
|
||||||
}) * (3.0 / (dim as f64)).sqrt();
|
|
||||||
|
|
||||||
// initialize the rotation step
|
|
||||||
let mut rot_step = DMatrix::<f64>::identity(dim, dim);
|
|
||||||
let max_freq = 4;
|
|
||||||
for n in (0..dim).step_by(2) {
|
|
||||||
let ang = PI * ((n % max_freq) as f64) / (time_res as f64);
|
|
||||||
let ang_cos = ang.cos();
|
|
||||||
let ang_sin = ang.sin();
|
|
||||||
rot_step[(n, n)] = ang_cos;
|
|
||||||
rot_step[(n+1, n)] = ang_sin;
|
|
||||||
rot_step[(n, n+1)] = -ang_sin;
|
|
||||||
rot_step[(n+1, n+1)] = ang_cos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the eigenvalues
|
|
||||||
let mut eigval_series = Vec::<OVector<Complex<f64>, Dyn>>::with_capacity(time_res);
|
|
||||||
eigval_series.push(rand_mat.complex_eigenvalues());
|
|
||||||
for _ in 1..time_res {
|
|
||||||
rand_mat = &rot_step * rand_mat;
|
|
||||||
eigval_series.push(rand_mat.complex_eigenvalues());
|
|
||||||
}
|
|
||||||
eigval_series
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dynamic single float matrices */
|
|
||||||
/*pub fn rand_eigval_series<N>(time_res: usize) -> Vec<OVector<Complex<f32>, Dyn>>
|
|
||||||
where
|
|
||||||
N: ToTypenum + DimName + DimSub<U1>,
|
|
||||||
DefaultAllocator:
|
|
||||||
Allocator<N> +
|
|
||||||
Allocator<N, N> +
|
|
||||||
Allocator<<N as DimSub<U1>>::Output> +
|
|
||||||
Allocator<N, <N as DimSub<U1>>::Output>
|
|
||||||
{
|
|
||||||
// initialize the random matrix
|
|
||||||
let dim = N::try_to_usize().unwrap();
|
|
||||||
let mut rand_mat = DMatrix::<f32>::from_fn(dim, dim, |j, k| {
|
|
||||||
let n = j*dim + k;
|
|
||||||
(E as f32)*((n*n) as f32) % 2.0_f32 - 1.0_f32
|
|
||||||
}) * (3.0_f32 / (dim as f32)).sqrt();
|
|
||||||
|
|
||||||
// initialize the rotation step
|
|
||||||
let mut rot_step = DMatrix::<f32>::identity(dim, dim);
|
|
||||||
let max_freq = 4;
|
|
||||||
for n in (0..dim).step_by(2) {
|
|
||||||
let ang = (PI as f32) * ((n % max_freq) as f32) / (time_res as f32);
|
|
||||||
let ang_cos = ang.cos();
|
|
||||||
let ang_sin = ang.sin();
|
|
||||||
rot_step[(n, n)] = ang_cos;
|
|
||||||
rot_step[(n+1, n)] = ang_sin;
|
|
||||||
rot_step[(n, n+1)] = -ang_sin;
|
|
||||||
rot_step[(n+1, n+1)] = ang_cos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the eigenvalues
|
|
||||||
let mut eigval_series = Vec::<OVector<Complex<f32>, Dyn>>::with_capacity(time_res);
|
|
||||||
eigval_series.push(rand_mat.complex_eigenvalues());
|
|
||||||
for _ in 1..time_res {
|
|
||||||
rand_mat = &rot_step * rand_mat;
|
|
||||||
eigval_series.push(rand_mat.complex_eigenvalues());
|
|
||||||
}
|
|
||||||
eigval_series
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/* static matrices. should only be used when the dimension is really small */
|
|
||||||
/*pub fn rand_eigval_series<N>(time_res: usize) -> Vec<OVector<Complex<f64>, N>>
|
|
||||||
where
|
|
||||||
N: ToTypenum + DimName + DimSub<U1>,
|
|
||||||
DefaultAllocator:
|
|
||||||
Allocator<N> +
|
|
||||||
Allocator<N, N> +
|
|
||||||
Allocator<<N as DimSub<U1>>::Output> +
|
|
||||||
Allocator<N, <N as DimSub<U1>>::Output>
|
|
||||||
{
|
|
||||||
// initialize the random matrix
|
|
||||||
let dim = N::try_to_usize().unwrap();
|
|
||||||
let mut rand_mat = OMatrix::<f64, N, N>::from_fn(|j, k| {
|
|
||||||
let n = j*dim + k;
|
|
||||||
E*((n*n) as f64) % 2.0 - 1.0
|
|
||||||
}) * (3.0 / (dim as f64)).sqrt();
|
|
||||||
/*let mut rand_mat = OMatrix::<f64, N, N>::identity();*/
|
|
||||||
|
|
||||||
// initialize the rotation step
|
|
||||||
let mut rot_step = OMatrix::<f64, N, N>::identity();
|
|
||||||
let max_freq = 4;
|
|
||||||
for n in (0..dim).step_by(2) {
|
|
||||||
let ang = PI * ((n % max_freq) as f64) / (time_res as f64);
|
|
||||||
let ang_cos = ang.cos();
|
|
||||||
let ang_sin = ang.sin();
|
|
||||||
rot_step[(n, n)] = ang_cos;
|
|
||||||
rot_step[(n+1, n)] = ang_sin;
|
|
||||||
rot_step[(n, n+1)] = -ang_sin;
|
|
||||||
rot_step[(n+1, n+1)] = ang_cos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the eigenvalues
|
|
||||||
let mut eigval_series = Vec::<OVector<Complex<f64>, N>>::with_capacity(time_res);
|
|
||||||
eigval_series.push(rand_mat.complex_eigenvalues());
|
|
||||||
for _ in 1..time_res {
|
|
||||||
rand_mat = &rot_step * rand_mat;
|
|
||||||
eigval_series.push(rand_mat.complex_eigenvalues());
|
|
||||||
}
|
|
||||||
eigval_series
|
|
||||||
}*/
|
|
||||||
|
|
||||||
/* another attempt at static matrices. i couldn't get the types to work out */
|
|
||||||
/*pub fn random_eigval_series<const N: usize>(time_res: usize) -> Vec<OVector<Complex<f64>, Const<N>>>
|
|
||||||
where
|
|
||||||
Const<N>: ToTypenum,
|
|
||||||
<Const<N> as ToTypenum>::Typenum: Sub<UInt<UTerm, B1>>,
|
|
||||||
<<Const<N> as ToTypenum>::Typenum as Sub<UInt<UTerm, B1>>>::Output: ToConst
|
|
||||||
{
|
|
||||||
// initialize the random matrix
|
|
||||||
/*let mut rand_mat = SMatrix::<f64, N, N>::zeros();
|
|
||||||
for n in 0..N*N {
|
|
||||||
rand_mat[n] = E*((n*n) as f64) % 2.0 - 1.0;
|
|
||||||
}*/
|
|
||||||
let rand_mat = OMatrix::<f64, Const<N>, Const<N>>::from_fn(|j, k| {
|
|
||||||
let n = j*N + k;
|
|
||||||
E*((n*n) as f64) % 2.0 - 1.0
|
|
||||||
});
|
|
||||||
|
|
||||||
// initialize the rotation step
|
|
||||||
let mut rot_step = OMatrix::<f64, Const<N>, Const<N>>::identity();
|
|
||||||
let max_freq = 4;
|
|
||||||
for n in (0..N).step_by(2) {
|
|
||||||
let ang = PI * ((n % max_freq) as f64) / (time_res as f64);
|
|
||||||
let ang_cos = ang.cos();
|
|
||||||
let ang_sin = ang.sin();
|
|
||||||
rot_step[(n, n)] = ang_cos;
|
|
||||||
rot_step[(n+1, n)] = ang_sin;
|
|
||||||
rot_step[(n, n+1)] = -ang_sin;
|
|
||||||
rot_step[(n+1, n+1)] = ang_cos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the eigenvalues
|
|
||||||
let mut eigvals = Vec::<OVector<Complex<f64>, Const<N>>>::with_capacity(time_res);
|
|
||||||
unsafe { eigvals.set_len(time_res); }
|
|
||||||
for t in 0..time_res {
|
|
||||||
eigvals[t] = rand_mat.complex_eigenvalues();
|
|
||||||
}
|
|
||||||
eigvals
|
|
||||||
}*/
|
|
@ -1,78 +0,0 @@
|
|||||||
use nalgebra::*;
|
|
||||||
use std::f64::consts::PI as PI;
|
|
||||||
use sycamore::{prelude::*, rt::{JsCast, JsValue}};
|
|
||||||
use web_sys::window;
|
|
||||||
|
|
||||||
mod engine;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// set up a config option that forwards panic messages to `console.error`
|
|
||||||
#[cfg(feature = "console_error_panic_hook")]
|
|
||||||
console_error_panic_hook::set_once();
|
|
||||||
|
|
||||||
sycamore::render(|| {
|
|
||||||
let time_res: usize = 100;
|
|
||||||
let time_step = create_signal(0.0);
|
|
||||||
let run_time_report = create_signal(-1.0);
|
|
||||||
let display = create_node_ref();
|
|
||||||
|
|
||||||
on_mount(move || {
|
|
||||||
let performance = window().unwrap().performance().unwrap();
|
|
||||||
let start_time = performance.now();
|
|
||||||
let eigval_series = engine::rand_eigval_series::<U60>(time_res);
|
|
||||||
let run_time = performance.now() - start_time;
|
|
||||||
run_time_report.set(run_time);
|
|
||||||
|
|
||||||
let canvas = display
|
|
||||||
.get::<DomNode>()
|
|
||||||
.unchecked_into::<web_sys::HtmlCanvasElement>();
|
|
||||||
let ctx = canvas
|
|
||||||
.get_context("2d")
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.dyn_into::<web_sys::CanvasRenderingContext2d>()
|
|
||||||
.unwrap();
|
|
||||||
ctx.set_fill_style(&JsValue::from("white"));
|
|
||||||
|
|
||||||
create_effect(move || {
|
|
||||||
// center and normalize the coordinate system
|
|
||||||
let width = canvas.width() as f64;
|
|
||||||
let height = canvas.height() as f64;
|
|
||||||
ctx.set_transform(1.0, 0.0, 0.0, -1.0, 0.5*width, 0.5*height).unwrap();
|
|
||||||
|
|
||||||
// clear the previous frame
|
|
||||||
ctx.clear_rect(-0.5*width, -0.5*width, width, height);
|
|
||||||
|
|
||||||
// find the resolution
|
|
||||||
const R_DISP: f64 = 1.5;
|
|
||||||
let res = width / (2.0*R_DISP);
|
|
||||||
|
|
||||||
// draw the eigenvalues
|
|
||||||
let eigvals = &eigval_series[time_step.get() as usize];
|
|
||||||
for n in 0..eigvals.len() {
|
|
||||||
ctx.begin_path();
|
|
||||||
ctx.arc(
|
|
||||||
/* typecast only needed for single float version */
|
|
||||||
res * f64::from(eigvals[n].re),
|
|
||||||
res * f64::from(eigvals[n].im),
|
|
||||||
3.0,
|
|
||||||
0.0, 2.0*PI
|
|
||||||
).unwrap();
|
|
||||||
ctx.fill();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
view! {
|
|
||||||
div(id="app") {
|
|
||||||
div { (run_time_report.get()) " ms" }
|
|
||||||
canvas(ref=display, width="600", height="600")
|
|
||||||
input(
|
|
||||||
type="range",
|
|
||||||
max=(time_res - 1).to_string(),
|
|
||||||
bind:valueAsNumber=time_step
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
3
lang-trials/rust/.gitignore
vendored
3
lang-trials/rust/.gitignore
vendored
@ -1,3 +1,2 @@
|
|||||||
target/*
|
target/*
|
||||||
dist/*
|
dist/*
|
||||||
Cargo.lock
|
|
2
lang-trials/scala-benchmark/.gitignore
vendored
2
lang-trials/scala-benchmark/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
target
|
|
||||||
sbt.json
|
|
@ -1,9 +0,0 @@
|
|||||||
enablePlugins(ScalaJSPlugin)
|
|
||||||
|
|
||||||
name := "Circular Law"
|
|
||||||
scalaVersion := "3.4.2"
|
|
||||||
scalaJSUseMainModuleInitializer := true
|
|
||||||
|
|
||||||
libraryDependencies += "com.raquo" %%% "laminar" % "17.0.0"
|
|
||||||
libraryDependencies += "ai.dragonfly" %%% "slash" % "0.3.1"
|
|
||||||
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0"
|
|
@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>The circular law</title>
|
|
||||||
<script type="text/javascript" src="./target/scala-3.4.2/circular-law-fastopt/main.js"></script>
|
|
||||||
<link rel="stylesheet" href="main.css"/>
|
|
||||||
</head>
|
|
||||||
<body></body>
|
|
||||||
</html>
|
|
@ -1,23 +0,0 @@
|
|||||||
body {
|
|
||||||
margin-left: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
color: #fcfcfc;
|
|
||||||
background-color: #202020;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
float: left;
|
|
||||||
background-color: #020202;
|
|
||||||
border-radius: 10px;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
sbt.version=1.10.1
|
|
@ -1 +0,0 @@
|
|||||||
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
|
|
@ -1,89 +0,0 @@
|
|||||||
import com.raquo.laminar.api.L.{*, given}
|
|
||||||
import narr.*
|
|
||||||
import org.scalajs.dom
|
|
||||||
import org.scalajs.dom.document
|
|
||||||
import scala.math.{cos, sin}
|
|
||||||
import slash.matrix.Matrix
|
|
||||||
import slash.matrix.decomposition.Eigen
|
|
||||||
|
|
||||||
object CircularLawApp:
|
|
||||||
val canvas = canvasTag(widthAttr := 600, heightAttr := 600)
|
|
||||||
val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D]
|
|
||||||
|
|
||||||
val (eigvalSeries, runTimeReport) = randEigvalSeries[60]()
|
|
||||||
val timeStepState = Var("0")
|
|
||||||
|
|
||||||
def draw(timeStep: String): Unit =
|
|
||||||
// center and normalize the coordinate system
|
|
||||||
val width = canvas.ref.width
|
|
||||||
val height = canvas.ref.height
|
|
||||||
ctx.setTransform(1d, 0d, 0d, -1d, 0.5*width, 0.5*height)
|
|
||||||
|
|
||||||
// clear the previous frame
|
|
||||||
ctx.clearRect(-0.5*width, -0.5*width, width, height)
|
|
||||||
|
|
||||||
// find the resolution
|
|
||||||
val rDisp: Double = 1.5
|
|
||||||
val res = width / (2*rDisp)
|
|
||||||
|
|
||||||
// draw the eigenvalues
|
|
||||||
val eigvals = eigvalSeries(timeStep.toInt)
|
|
||||||
for n <- 0 to eigvals(0).length-1 do
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(
|
|
||||||
res * eigvals(0)(n),
|
|
||||||
res * eigvals(1)(n),
|
|
||||||
3d,
|
|
||||||
0d, 2*math.Pi
|
|
||||||
)
|
|
||||||
ctx.fill()
|
|
||||||
|
|
||||||
def eigvalsRotated[N <: Int](A: Matrix[N, N], time: Double)(using ValueOf[N]): (NArray[Double], NArray[Double]) =
|
|
||||||
// create transformation
|
|
||||||
val maxFreq = 4
|
|
||||||
val T = Matrix.identity[N, N]
|
|
||||||
val dim: Int = valueOf[N]
|
|
||||||
for n <- 0 to dim by 2 do
|
|
||||||
val a = cos(math.Pi * time * (n % maxFreq))
|
|
||||||
val b = sin(math.Pi * time * (n % maxFreq))
|
|
||||||
T(n, n) = a
|
|
||||||
T(n+1, n) = b
|
|
||||||
T(n, n+1) = -b
|
|
||||||
T(n+1, n+1) = a
|
|
||||||
|
|
||||||
// find eigenvalues
|
|
||||||
val eigen = Eigen(T*A)
|
|
||||||
(
|
|
||||||
eigen.realEigenvalues.asInstanceOf[NArray[Double]],
|
|
||||||
eigen.imaginaryEigenvalues.asInstanceOf[NArray[Double]]
|
|
||||||
)
|
|
||||||
|
|
||||||
def randEigvalSeries[N <: Int]()(using ValueOf[N]): (List[(NArray[Double], NArray[Double])], String) =
|
|
||||||
val timeRes = 100
|
|
||||||
val dim: Int = valueOf[N]
|
|
||||||
val startTime = System.currentTimeMillis()
|
|
||||||
val A = new Matrix[N, N](
|
|
||||||
NArray.tabulate(dim*dim)(k => (math.E*k*k) % 2 - 1)
|
|
||||||
).times(math.sqrt(3d / dim))
|
|
||||||
val series = List.tabulate(timeRes)(t => eigvalsRotated(A, t.toDouble / timeRes))
|
|
||||||
val runTime = System.currentTimeMillis() - startTime
|
|
||||||
(series, runTime.toString() + " ms")
|
|
||||||
|
|
||||||
def main(args: Array[String]): Unit =
|
|
||||||
ctx.fillStyle = "white"
|
|
||||||
|
|
||||||
lazy val app = div(
|
|
||||||
idAttr := "app",
|
|
||||||
div(runTimeReport),
|
|
||||||
canvas,
|
|
||||||
input(
|
|
||||||
typ := "range",
|
|
||||||
maxAttr := (eigvalSeries.length-1).toString,
|
|
||||||
controlled(
|
|
||||||
value <-- timeStepState.signal,
|
|
||||||
onInput.mapToValue --> timeStepState.writer
|
|
||||||
),
|
|
||||||
timeStepState.signal --> draw
|
|
||||||
)
|
|
||||||
)
|
|
||||||
renderOnDomContentLoaded(document.body, app)
|
|
2
lang-trials/scala/.gitignore
vendored
2
lang-trials/scala/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
target
|
|
||||||
sbt.json
|
|
@ -1,12 +0,0 @@
|
|||||||
enablePlugins(ScalaJSPlugin)
|
|
||||||
|
|
||||||
name := "Lattice Circle"
|
|
||||||
scalaVersion := "3.4.2"
|
|
||||||
|
|
||||||
// This is an application with a main method
|
|
||||||
scalaJSUseMainModuleInitializer := true
|
|
||||||
|
|
||||||
libraryDependencies += "com.raquo" %%% "laminar" % "17.0.0"
|
|
||||||
/*libraryDependencies += "org.scalanlp" %% "breeze" % "2.1.0"*/
|
|
||||||
libraryDependencies += "ai.dragonfly" %%% "slash" % "0.3.1"
|
|
||||||
libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0"
|
|
@ -1,10 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Lattice circle</title>
|
|
||||||
<script type="text/javascript" src="./target/scala-3.4.2/lattice-circle-fastopt/main.js"></script>
|
|
||||||
<link rel="stylesheet" href="main.css"/>
|
|
||||||
</head>
|
|
||||||
<body></body>
|
|
||||||
</html>
|
|
@ -1,45 +0,0 @@
|
|||||||
body {
|
|
||||||
margin-left: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
color: #fcfcfc;
|
|
||||||
background-color: #202020;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
color: inherit;
|
|
||||||
background-color: #020202;
|
|
||||||
border: 1px solid #606060;
|
|
||||||
min-width: 40px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.point-1 {
|
|
||||||
border-color: #ba5d09;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.point-2 {
|
|
||||||
border-color: #0e8a06;
|
|
||||||
}
|
|
||||||
|
|
||||||
input.point-3 {
|
|
||||||
border-color: #8951fb;
|
|
||||||
}
|
|
||||||
|
|
||||||
#data-panel {
|
|
||||||
float: left;
|
|
||||||
margin-left: 20px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: auto auto;
|
|
||||||
gap: 10px 10px;
|
|
||||||
width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#data-panel > div {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
float: left;
|
|
||||||
background-color: #020202;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
sbt.version=1.10.1
|
|
@ -1 +0,0 @@
|
|||||||
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
|
|
@ -1,160 +0,0 @@
|
|||||||
// based on the Laminar example app
|
|
||||||
//
|
|
||||||
// https://github.com/raquo/laminar-examples/blob/master/src/main/scala/App.scala
|
|
||||||
//
|
|
||||||
// and Li Haoyi's example canvas app
|
|
||||||
//
|
|
||||||
// http://www.lihaoyi.com/hands-on-scala-js/#MakingaCanvasApp
|
|
||||||
//
|
|
||||||
|
|
||||||
import com.raquo.laminar.api.L.{*, given}
|
|
||||||
import narr.*
|
|
||||||
import org.scalajs.dom
|
|
||||||
import org.scalajs.dom.document
|
|
||||||
import scala.math
|
|
||||||
import slash.matrix.*
|
|
||||||
|
|
||||||
class Circle(var centerX: Double, var centerY: Double, var radius: Double)
|
|
||||||
|
|
||||||
object LatticeCircleApp:
|
|
||||||
val canvas = canvasTag(widthAttr := 600, heightAttr := 600)
|
|
||||||
val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D]
|
|
||||||
val data = List("-1", "0", "0", "-1", "1", "0").map(Var(_))
|
|
||||||
|
|
||||||
def circThru(points: Matrix[3, 2]): Option[Circle] =
|
|
||||||
// build the matrix that maps the circle's coefficient vector to the
|
|
||||||
// negative of the linear part of the circle's equation, evaluated at the
|
|
||||||
// given points
|
|
||||||
val negLinPart = Matrix.ones[3, 3]
|
|
||||||
negLinPart.setMatrix(0, 0, points * 2.0)
|
|
||||||
|
|
||||||
// find the quadrdatic part of the circle's equation, evaluated at the given
|
|
||||||
// points
|
|
||||||
val quadPart = Matrix[3, 1](
|
|
||||||
NArray.tabulate[Double](3)(
|
|
||||||
k => points(k, 0)*points(k, 0) + points(k, 1)*points(k, 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// find the circle's coefficient vector, and from there its center and
|
|
||||||
// radius
|
|
||||||
try
|
|
||||||
val coeffs = negLinPart.solve(quadPart)
|
|
||||||
val centerX = coeffs(0, 0)
|
|
||||||
val centerY = coeffs(1, 0)
|
|
||||||
Some(Circle(
|
|
||||||
centerX,
|
|
||||||
centerY,
|
|
||||||
math.sqrt(coeffs(2, 0) + centerX*centerX + centerY*centerY)
|
|
||||||
))
|
|
||||||
catch
|
|
||||||
_ => return None
|
|
||||||
|
|
||||||
def draw(): Unit =
|
|
||||||
// center and normalize the coordinate system
|
|
||||||
val width = canvas.ref.width
|
|
||||||
val height = canvas.ref.height
|
|
||||||
ctx.setTransform(1.0, 0.0, 0.0, -1.0, 0.5*width, 0.5*height)
|
|
||||||
|
|
||||||
// clear the previous frame
|
|
||||||
ctx.clearRect(-0.5*width, -0.5*width, width, height)
|
|
||||||
|
|
||||||
// find the resolution
|
|
||||||
val rDisp = 5.0
|
|
||||||
val res = width / (2.0*rDisp)
|
|
||||||
|
|
||||||
// set colors
|
|
||||||
val highlightStyle = "white"
|
|
||||||
val gridStyle = "#404040"
|
|
||||||
val pointFillStyles = List("#ba5d09", "#0e8a06", "#8951fb")
|
|
||||||
val pointStrokeStyles = List("#f89142", "#58c145", "#c396fc")
|
|
||||||
|
|
||||||
// draw the grid
|
|
||||||
val rGrid = (rDisp - 0.01).floor.toInt
|
|
||||||
val edgeScr = res * rDisp
|
|
||||||
ctx.strokeStyle = gridStyle
|
|
||||||
for t <- -rGrid to rGrid do
|
|
||||||
val tScr = res * t
|
|
||||||
|
|
||||||
// draw horizontal grid line
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(-edgeScr, tScr)
|
|
||||||
ctx.lineTo(edgeScr, tScr)
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
// draw vertical grid line
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(tScr, -edgeScr)
|
|
||||||
ctx.lineTo(tScr, edgeScr)
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
// find and draw the circle through the given points
|
|
||||||
val dataNow = NArray.tabulate(6)(n =>
|
|
||||||
try
|
|
||||||
data(n).signal.now().toDouble
|
|
||||||
catch
|
|
||||||
_ => Double.NaN
|
|
||||||
)
|
|
||||||
if dataNow.forall(t => t == t.floor) then
|
|
||||||
// all of the coordinates are integer and non-NaN
|
|
||||||
val points = Matrix[3, 2](dataNow)
|
|
||||||
circThru(points) match
|
|
||||||
case Some(circ) =>
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.strokeStyle = highlightStyle
|
|
||||||
ctx.arc(
|
|
||||||
res * circ.centerX,
|
|
||||||
res * circ.centerY,
|
|
||||||
res * circ.radius,
|
|
||||||
0.0, 2.0*math.Pi
|
|
||||||
)
|
|
||||||
ctx.stroke()
|
|
||||||
case None =>
|
|
||||||
|
|
||||||
// draw the data points
|
|
||||||
for n <- 0 to 2 do
|
|
||||||
val indX = 2*n
|
|
||||||
val indY = indX + 1
|
|
||||||
if
|
|
||||||
dataNow(indX) == dataNow(indX).floor &&
|
|
||||||
dataNow(indY) == dataNow(indY).floor
|
|
||||||
then
|
|
||||||
ctx.beginPath()
|
|
||||||
ctx.fillStyle = pointFillStyles(n)
|
|
||||||
ctx.strokeStyle = pointStrokeStyles(n)
|
|
||||||
ctx.arc(
|
|
||||||
res * dataNow(indX),
|
|
||||||
res * dataNow(indY),
|
|
||||||
3.0,
|
|
||||||
0.0, 2.0*math.Pi
|
|
||||||
)
|
|
||||||
ctx.fill()
|
|
||||||
ctx.stroke()
|
|
||||||
|
|
||||||
def coordInput(n: Int): Input =
|
|
||||||
input(
|
|
||||||
typ := "number",
|
|
||||||
cls := s"point-${(1.0 + 0.5*n).floor.toInt}",
|
|
||||||
controlled(
|
|
||||||
value <-- data(n).signal,
|
|
||||||
onInput.mapToValue --> data(n).writer
|
|
||||||
),
|
|
||||||
data(n).signal --> { _ => draw() }
|
|
||||||
)
|
|
||||||
|
|
||||||
def main(args: Array[String]): Unit =
|
|
||||||
lazy val app = div(
|
|
||||||
canvas,
|
|
||||||
div(
|
|
||||||
idAttr := "data-panel",
|
|
||||||
div("x"),
|
|
||||||
div("y"),
|
|
||||||
coordInput(0),
|
|
||||||
coordInput(1),
|
|
||||||
coordInput(2),
|
|
||||||
coordInput(3),
|
|
||||||
coordInput(4),
|
|
||||||
coordInput(5)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
renderOnDomContentLoaded(document.body, app)
|
|
Loading…
Reference in New Issue
Block a user