From c376fcdad8135c0c5cd847548ed5d8db32795a00 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Wed, 7 Aug 2024 13:32:12 -0700 Subject: [PATCH 1/7] Hack together a "Hello, world" in Scala with Laminar --- lang-trials/scala/.gitignore | 2 + lang-trials/scala/build.sbt | 12 + lang-trials/scala/index.html | 10 + lang-trials/scala/main.css | 50 ++++ lang-trials/scala/project/build.properties | 1 + lang-trials/scala/project/plugins.sbt | 1 + .../src/main/scala/LatticeCircleApp.scala | 253 ++++++++++++++++++ 7 files changed, 329 insertions(+) create mode 100644 lang-trials/scala/.gitignore create mode 100644 lang-trials/scala/build.sbt create mode 100644 lang-trials/scala/index.html create mode 100644 lang-trials/scala/main.css create mode 100644 lang-trials/scala/project/build.properties create mode 100644 lang-trials/scala/project/plugins.sbt create mode 100644 lang-trials/scala/src/main/scala/LatticeCircleApp.scala diff --git a/lang-trials/scala/.gitignore b/lang-trials/scala/.gitignore new file mode 100644 index 0000000..9f2a453 --- /dev/null +++ b/lang-trials/scala/.gitignore @@ -0,0 +1,2 @@ +target +sbt.json \ No newline at end of file diff --git a/lang-trials/scala/build.sbt b/lang-trials/scala/build.sbt new file mode 100644 index 0000000..908e7e9 --- /dev/null +++ b/lang-trials/scala/build.sbt @@ -0,0 +1,12 @@ +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" diff --git a/lang-trials/scala/index.html b/lang-trials/scala/index.html new file mode 100644 index 0000000..ff30e9f --- /dev/null +++ b/lang-trials/scala/index.html @@ -0,0 +1,10 @@ + + + + + Lattice circle + + + + + diff --git a/lang-trials/scala/main.css b/lang-trials/scala/main.css new file mode 100644 index 0000000..ea89d47 --- /dev/null +++ b/lang-trials/scala/main.css @@ -0,0 +1,50 @@ +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; +} + +#result-display { + margin-top: 10px; + font-weight: bold; +} + +canvas { + float: left; + background-color: #020202; + border-radius: 10px; +} diff --git a/lang-trials/scala/project/build.properties b/lang-trials/scala/project/build.properties new file mode 100644 index 0000000..ee4c672 --- /dev/null +++ b/lang-trials/scala/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.10.1 diff --git a/lang-trials/scala/project/plugins.sbt b/lang-trials/scala/project/plugins.sbt new file mode 100644 index 0000000..e5b2699 --- /dev/null +++ b/lang-trials/scala/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") diff --git a/lang-trials/scala/src/main/scala/LatticeCircleApp.scala b/lang-trials/scala/src/main/scala/LatticeCircleApp.scala new file mode 100644 index 0000000..602b2fc --- /dev/null +++ b/lang-trials/scala/src/main/scala/LatticeCircleApp.scala @@ -0,0 +1,253 @@ +// 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 breeze.linalg._*/ +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 dataBusList = List.tabulate(6)(_ => new EventBus[Double]) + val dataStream = dataBusList(0).events + .combineWith(dataBusList(1).events) + .combineWith(dataBusList(2).events) + .combineWith(dataBusList(3).events) + .combineWith(dataBusList(4).events) + .combineWith(dataBusList(5).events) + .map(dataTuple => NArray(dataTuple(0), dataTuple(1), dataTuple(2), dataTuple(3), dataTuple(4), dataTuple(5))) + .filter(data => data.forall(!_.isNaN())) + /* + val dataList = List(-1.0, 0.0, 0.0, -1.0, 1.0, 0.0).map(Var(_)) + val dataStream = dataList(0).signal + .combineWith(dataList(1).signal) + .combineWith(dataList(2).signal) + .combineWith(dataList(3).signal) + .combineWith(dataList(4).signal) + .combineWith(dataList(5).signal) + .map(dataTuple => NArray(dataTuple(0), dataTuple(1), dataTuple(2), dataTuple(3), dataTuple(4), dataTuple(5))) + */ + val pointStream = dataStream.map(data => Matrix[3, 2](data)) + /* Breeze version */ + /* + val pointStream = dataStream.map(data => new DenseMatrix(2, 3, Array(data(0), data(1), data(2), data(3), data(4), data(5)))) + */ + + /* Breeze version */ + /* + def circThru(points: DenseMatrix[Double]): 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 = DenseMatrix.horzcat( + 2.0*points.t, + DenseMatrix.ones[Double](3, 1) + ) + + // find the quadrdatic part of the circle's equation, evaluated at the given + // points + val quadPart = points(::, *).map(v => v dot v) + + // find the circle's coefficient vector, and from there its center and + // radius + val coeffs = negLinPart \ quadPart + val centerX = coeffs(0, 0) + val centerY = coeffs(1, 0) + Circle( + centerX, + centerY, + math.sqrt(coeffs(2, 0) + centerX*centerX + centerY*centerY) + ) + */ + + 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) + println("built neg lin part") + println(negLinPart) + + // 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) + ) + ) + println("build quad part") + println(quadPart) + + // 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(points: Matrix[3, 2]): 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 + 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 + ctx.beginPath() + ctx.fillStyle = pointFillStyles(n) + ctx.strokeStyle = pointStrokeStyles(n) + ctx.arc( + res * points(n, 0), + res * points(n, 1), + 3.0, + 0.0, 2.0*math.Pi + ) + ctx.fill() + ctx.stroke() + + def main(args: Array[String]): Unit = + lazy val app = div( + canvas, + div( + pointStream --> draw, + idAttr := "data-panel", + div("x"), + div("y"), + input(typ := "number", cls := "point-1", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(0))), + input(typ := "number", cls := "point-1", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(1))), + input(typ := "number", cls := "point-2", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(2))), + input(typ := "number", cls := "point-2", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(3))), + input(typ := "number", cls := "point-3", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(4))), + input(typ := "number", cls := "point-3", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(5))) + /* attempt to use controlled inputs */ + /* + input( + typ := "number", + cls := "point-1", + controlled( + value <-- dataList(0).signal, + inContext( + thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(0).writer + ) + ) + ), + input( + typ := "number", + cls := "point-1", + controlled( + value <-- dataList(1).signal, + inContext( + thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(1).writer + ) + ) + ), + input( + typ := "number", + cls := "point-2", + controlled( + value <-- dataList(2).signal, + inContext( + thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(2).writer + ) + ) + ), + input( + typ := "number", + cls := "point-2", + controlled( + value <-- dataList(3).signal, + inContext( + thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(3).writer + ) + ) + ), + input( + typ := "number", + cls := "point-3", + controlled( + value <-- dataList(4).signal, + inContext( + thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(4).writer + ) + ) + ), + input( + typ := "number", + cls := "point-3", + controlled( + value <-- dataList(5).signal, + inContext( + thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(5).writer + ) + ) + ) + */ + ) + ) + renderOnDomContentLoaded(document.body, app) From 4f30f3168667ea3f1b6067fb9b1eafe92b1be5ca Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Wed, 7 Aug 2024 13:36:48 -0700 Subject: [PATCH 2/7] Rust trial: Make git ignore Cargo.lock --- lang-trials/rust/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lang-trials/rust/.gitignore b/lang-trials/rust/.gitignore index 1d4e644..5b910ca 100644 --- a/lang-trials/rust/.gitignore +++ b/lang-trials/rust/.gitignore @@ -1,2 +1,3 @@ target/* -dist/* \ No newline at end of file +dist/* +Cargo.lock \ No newline at end of file From 0bd025dd14c819e7ad93d0dcd77b508a635ef97a Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Wed, 7 Aug 2024 13:40:09 -0700 Subject: [PATCH 3/7] Scala trial: clean up Laminar interface Also, drop unused Breeze code in favor of Slash. --- .../src/main/scala/LatticeCircleApp.scala | 207 +++++------------- 1 file changed, 57 insertions(+), 150 deletions(-) diff --git a/lang-trials/scala/src/main/scala/LatticeCircleApp.scala b/lang-trials/scala/src/main/scala/LatticeCircleApp.scala index 602b2fc..12ee36c 100644 --- a/lang-trials/scala/src/main/scala/LatticeCircleApp.scala +++ b/lang-trials/scala/src/main/scala/LatticeCircleApp.scala @@ -8,7 +8,6 @@ // import com.raquo.laminar.api.L.{*, given} -/*import breeze.linalg._*/ import narr.* import org.scalajs.dom import org.scalajs.dom.document @@ -20,57 +19,7 @@ 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 dataBusList = List.tabulate(6)(_ => new EventBus[Double]) - val dataStream = dataBusList(0).events - .combineWith(dataBusList(1).events) - .combineWith(dataBusList(2).events) - .combineWith(dataBusList(3).events) - .combineWith(dataBusList(4).events) - .combineWith(dataBusList(5).events) - .map(dataTuple => NArray(dataTuple(0), dataTuple(1), dataTuple(2), dataTuple(3), dataTuple(4), dataTuple(5))) - .filter(data => data.forall(!_.isNaN())) - /* - val dataList = List(-1.0, 0.0, 0.0, -1.0, 1.0, 0.0).map(Var(_)) - val dataStream = dataList(0).signal - .combineWith(dataList(1).signal) - .combineWith(dataList(2).signal) - .combineWith(dataList(3).signal) - .combineWith(dataList(4).signal) - .combineWith(dataList(5).signal) - .map(dataTuple => NArray(dataTuple(0), dataTuple(1), dataTuple(2), dataTuple(3), dataTuple(4), dataTuple(5))) - */ - val pointStream = dataStream.map(data => Matrix[3, 2](data)) - /* Breeze version */ - /* - val pointStream = dataStream.map(data => new DenseMatrix(2, 3, Array(data(0), data(1), data(2), data(3), data(4), data(5)))) - */ - - /* Breeze version */ - /* - def circThru(points: DenseMatrix[Double]): 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 = DenseMatrix.horzcat( - 2.0*points.t, - DenseMatrix.ones[Double](3, 1) - ) - - // find the quadrdatic part of the circle's equation, evaluated at the given - // points - val quadPart = points(::, *).map(v => v dot v) - - // find the circle's coefficient vector, and from there its center and - // radius - val coeffs = negLinPart \ quadPart - val centerX = coeffs(0, 0) - val centerY = coeffs(1, 0) - Circle( - centerX, - centerY, - math.sqrt(coeffs(2, 0) + centerX*centerX + centerY*centerY) - ) - */ + 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 @@ -78,8 +27,6 @@ object LatticeCircleApp: // given points val negLinPart = Matrix.ones[3, 3] negLinPart.setMatrix(0, 0, points * 2.0) - println("built neg lin part") - println(negLinPart) // find the quadrdatic part of the circle's equation, evaluated at the given // points @@ -88,8 +35,6 @@ object LatticeCircleApp: k => points(k, 0)*points(k, 0) + points(k, 1)*points(k, 1) ) ) - println("build quad part") - println(quadPart) // find the circle's coefficient vector, and from there its center and // radius @@ -105,7 +50,7 @@ object LatticeCircleApp: catch _ => return None - def draw(points: Matrix[3, 2]): Unit = + def draw(): Unit = // center and normalize the coordinate system val width = canvas.ref.width val height = canvas.ref.height @@ -144,110 +89,72 @@ object LatticeCircleApp: ctx.stroke() // find and draw the circle through the given points - 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 => + 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 - ctx.beginPath() - ctx.fillStyle = pointFillStyles(n) - ctx.strokeStyle = pointStrokeStyles(n) - ctx.arc( - res * points(n, 0), - res * points(n, 1), - 3.0, - 0.0, 2.0*math.Pi - ) - ctx.fill() - ctx.stroke() + 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( - pointStream --> draw, idAttr := "data-panel", div("x"), div("y"), - input(typ := "number", cls := "point-1", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(0))), - input(typ := "number", cls := "point-1", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(1))), - input(typ := "number", cls := "point-2", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(2))), - input(typ := "number", cls := "point-2", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(3))), - input(typ := "number", cls := "point-3", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(4))), - input(typ := "number", cls := "point-3", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(5))) - /* attempt to use controlled inputs */ - /* - input( - typ := "number", - cls := "point-1", - controlled( - value <-- dataList(0).signal, - inContext( - thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(0).writer - ) - ) - ), - input( - typ := "number", - cls := "point-1", - controlled( - value <-- dataList(1).signal, - inContext( - thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(1).writer - ) - ) - ), - input( - typ := "number", - cls := "point-2", - controlled( - value <-- dataList(2).signal, - inContext( - thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(2).writer - ) - ) - ), - input( - typ := "number", - cls := "point-2", - controlled( - value <-- dataList(3).signal, - inContext( - thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(3).writer - ) - ) - ), - input( - typ := "number", - cls := "point-3", - controlled( - value <-- dataList(4).signal, - inContext( - thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(4).writer - ) - ) - ), - input( - typ := "number", - cls := "point-3", - controlled( - value <-- dataList(5).signal, - inContext( - thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(5).writer - ) - ) - ) - */ + coordInput(0), + coordInput(1), + coordInput(2), + coordInput(3), + coordInput(4), + coordInput(5) ) ) renderOnDomContentLoaded(document.body, app) From 6b0fad89dc34d4af20649105ffb6f10ad79f7e65 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Thu, 8 Aug 2024 00:26:26 -0700 Subject: [PATCH 4/7] Scala trial: write benchmark --- lang-trials/scala-benchmark/.gitignore | 2 + lang-trials/scala-benchmark/build.sbt | 9 ++ lang-trials/scala-benchmark/index.html | 10 ++ lang-trials/scala-benchmark/main.css | 22 +++++ .../scala-benchmark/project/build.properties | 1 + .../scala-benchmark/project/plugins.sbt | 1 + .../src/main/scala/CircularLawApp.scala | 91 +++++++++++++++++++ 7 files changed, 136 insertions(+) create mode 100644 lang-trials/scala-benchmark/.gitignore create mode 100644 lang-trials/scala-benchmark/build.sbt create mode 100644 lang-trials/scala-benchmark/index.html create mode 100644 lang-trials/scala-benchmark/main.css create mode 100644 lang-trials/scala-benchmark/project/build.properties create mode 100644 lang-trials/scala-benchmark/project/plugins.sbt create mode 100644 lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala diff --git a/lang-trials/scala-benchmark/.gitignore b/lang-trials/scala-benchmark/.gitignore new file mode 100644 index 0000000..9f2a453 --- /dev/null +++ b/lang-trials/scala-benchmark/.gitignore @@ -0,0 +1,2 @@ +target +sbt.json \ No newline at end of file diff --git a/lang-trials/scala-benchmark/build.sbt b/lang-trials/scala-benchmark/build.sbt new file mode 100644 index 0000000..507885d --- /dev/null +++ b/lang-trials/scala-benchmark/build.sbt @@ -0,0 +1,9 @@ +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" diff --git a/lang-trials/scala-benchmark/index.html b/lang-trials/scala-benchmark/index.html new file mode 100644 index 0000000..f9eb11c --- /dev/null +++ b/lang-trials/scala-benchmark/index.html @@ -0,0 +1,10 @@ + + + + + The circular law + + + + + diff --git a/lang-trials/scala-benchmark/main.css b/lang-trials/scala-benchmark/main.css new file mode 100644 index 0000000..a89c3bc --- /dev/null +++ b/lang-trials/scala-benchmark/main.css @@ -0,0 +1,22 @@ +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; +} + +input { + margin-top: 5px; +} \ No newline at end of file diff --git a/lang-trials/scala-benchmark/project/build.properties b/lang-trials/scala-benchmark/project/build.properties new file mode 100644 index 0000000..ee4c672 --- /dev/null +++ b/lang-trials/scala-benchmark/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.10.1 diff --git a/lang-trials/scala-benchmark/project/plugins.sbt b/lang-trials/scala-benchmark/project/plugins.sbt new file mode 100644 index 0000000..e5b2699 --- /dev/null +++ b/lang-trials/scala-benchmark/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") diff --git a/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala b/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala new file mode 100644 index 0000000..2f74cd3 --- /dev/null +++ b/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala @@ -0,0 +1,91 @@ +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) = randomEigvalSeries[60]() + val timeVar = Var("0") + + def draw(timeStr: 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(timeStr.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 randomEigvalSeries[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 endTime = System.currentTimeMillis() + val runTime = endTime - 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", + minAttr := "0", + maxAttr := (eigvalSeries.length-1).toString, + controlled( + value <-- timeVar.signal, + onInput.mapToValue --> timeVar.writer + ), + timeVar.signal --> draw + ) + ) + renderOnDomContentLoaded(document.body, app) From 0b3fe689cd6e8e1cd37f2d4905a25becc6acaa94 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 9 Aug 2024 15:12:44 -0700 Subject: [PATCH 5/7] Rust trial: write benchmark --- lang-trials/rust-benchmark/.gitignore | 3 + lang-trials/rust-benchmark/Cargo.toml | 35 +++++ lang-trials/rust-benchmark/index.html | 9 ++ lang-trials/rust-benchmark/main.css | 23 +++ lang-trials/rust-benchmark/notes | 13 ++ lang-trials/rust-benchmark/src/engine.rs | 176 +++++++++++++++++++++++ lang-trials/rust-benchmark/src/main.rs | 86 +++++++++++ 7 files changed, 345 insertions(+) create mode 100644 lang-trials/rust-benchmark/.gitignore create mode 100644 lang-trials/rust-benchmark/Cargo.toml create mode 100644 lang-trials/rust-benchmark/index.html create mode 100644 lang-trials/rust-benchmark/main.css create mode 100644 lang-trials/rust-benchmark/notes create mode 100644 lang-trials/rust-benchmark/src/engine.rs create mode 100644 lang-trials/rust-benchmark/src/main.rs diff --git a/lang-trials/rust-benchmark/.gitignore b/lang-trials/rust-benchmark/.gitignore new file mode 100644 index 0000000..5b910ca --- /dev/null +++ b/lang-trials/rust-benchmark/.gitignore @@ -0,0 +1,3 @@ +target/* +dist/* +Cargo.lock \ No newline at end of file diff --git a/lang-trials/rust-benchmark/Cargo.toml b/lang-trials/rust-benchmark/Cargo.toml new file mode 100644 index 0000000..8dde7b0 --- /dev/null +++ b/lang-trials/rust-benchmark/Cargo.toml @@ -0,0 +1,35 @@ +[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 diff --git a/lang-trials/rust-benchmark/index.html b/lang-trials/rust-benchmark/index.html new file mode 100644 index 0000000..82823fc --- /dev/null +++ b/lang-trials/rust-benchmark/index.html @@ -0,0 +1,9 @@ + + + + + The circular law + + + + diff --git a/lang-trials/rust-benchmark/main.css b/lang-trials/rust-benchmark/main.css new file mode 100644 index 0000000..f79e62c --- /dev/null +++ b/lang-trials/rust-benchmark/main.css @@ -0,0 +1,23 @@ +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; +} \ No newline at end of file diff --git a/lang-trials/rust-benchmark/notes b/lang-trials/rust-benchmark/notes new file mode 100644 index 0000000..79a4030 --- /dev/null +++ b/lang-trials/rust-benchmark/notes @@ -0,0 +1,13 @@ +in profiling, most time is being spent in the `reflect` method: + +f64: + sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::h7899977a4ba0b1d3 + sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::hc337c3cb6e3b4061 + sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect_rows::h43d0f6838d0c2833 + +f32: + sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::h0e8ec322f198f847 + sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::h9928bdd5e72743ea + sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::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 diff --git a/lang-trials/rust-benchmark/src/engine.rs b/lang-trials/rust-benchmark/src/engine.rs new file mode 100644 index 0000000..3b2b290 --- /dev/null +++ b/lang-trials/rust-benchmark/src/engine.rs @@ -0,0 +1,176 @@ +use nalgebra::{*, allocator::Allocator}; +use std::f64::consts::{PI, E}; +use web_sys::console; +/*use std::ops::Sub;*/ +/*use typenum::{B1, UInt, UTerm};*/ + +/*pub fn eigvals_rotated(A: SMatrix, time: f64): complex_eigenvalues(&self) -> OVector, D>*/ + +/* static matrices. should only be used when the dimension is really small */ +/*pub fn rand_eigval_series(time_res: usize) -> Vec, N>> + where + N: ToTypenum + DimName + DimSub, + DefaultAllocator: + Allocator + + Allocator + + Allocator<>::Output> + + Allocator>::Output> +{ + // initialize the random matrix + let dim = N::try_to_usize().unwrap(); + console::log_1(&format!("dimension {dim}").into()); + let mut rand_mat = OMatrix::::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::::identity();*/ + + // initialize the rotation step + let mut rot_step = OMatrix::::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::, N>>::with_capacity(time_res); + console::log_1(&"before engine eigenvalues".into()); + eigval_series.push(rand_mat.complex_eigenvalues()); + console::log_1(&"after engine eigenvalues".into()); + 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(time_res: usize) -> Vec, Const>> + where + Const: ToTypenum, + as ToTypenum>::Typenum: Sub>, + < as ToTypenum>::Typenum as Sub>>::Output: ToConst +{ + // initialize the random matrix + /*let mut rand_mat = SMatrix::::zeros(); + for n in 0..N*N { + rand_mat[n] = E*((n*n) as f64) % 2.0 - 1.0; + }*/ + let rand_mat = OMatrix::, Const>::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::, Const>::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::, Const>>::with_capacity(time_res); + unsafe { eigvals.set_len(time_res); } + for t in 0..time_res { + eigvals[t] = rand_mat.complex_eigenvalues(); + } + eigvals +}*/ + +/* dynamic matrices */ +pub fn rand_eigval_series(time_res: usize) -> Vec, Dyn>> + where + N: ToTypenum + DimName + DimSub, + DefaultAllocator: + Allocator + + Allocator + + Allocator<>::Output> + + Allocator>::Output> +{ + // initialize the random matrix + let dim = N::try_to_usize().unwrap(); + console::log_1(&format!("dimension {dim}").into()); + let mut rand_mat = DMatrix::::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::::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::, Dyn>>::with_capacity(time_res); + console::log_1(&"before engine eigenvalues".into()); + eigval_series.push(rand_mat.complex_eigenvalues()); + console::log_1(&"after engine eigenvalues".into()); + 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(time_res: usize) -> Vec, Dyn>> + where + N: ToTypenum + DimName + DimSub, + DefaultAllocator: + Allocator + + Allocator + + Allocator<>::Output> + + Allocator>::Output> +{ + // initialize the random matrix + let dim = N::try_to_usize().unwrap(); + console::log_1(&format!("dimension {dim}").into()); + let mut rand_mat = DMatrix::::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::::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::, Dyn>>::with_capacity(time_res); + console::log_1(&"before engine eigenvalues".into()); + eigval_series.push(rand_mat.complex_eigenvalues()); + console::log_1(&"after engine eigenvalues".into()); + for _ in 1..time_res { + rand_mat = &rot_step * rand_mat; + eigval_series.push(rand_mat.complex_eigenvalues()); + } + eigval_series +}*/ \ No newline at end of file diff --git a/lang-trials/rust-benchmark/src/main.rs b/lang-trials/rust-benchmark/src/main.rs new file mode 100644 index 0000000..7143e20 --- /dev/null +++ b/lang-trials/rust-benchmark/src/main.rs @@ -0,0 +1,86 @@ +use nalgebra::*; +use std::f64::consts::PI as PI; +use sycamore::{prelude::*, rt::{JsCast, JsValue}}; +use web_sys::{console, 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(); + + /*console::log_1(&"before test schur 60".into());*/ + /*let test_rand_mat = OMatrix::::identity();*/ + /*let test_rot_step = OMatrix::::identity();*/ + /*let test_schur = test_rand_mat.schur(); + console::log_1(&format!("after test schur").into()); + let test_eigvals = test_schur.complex_eigenvalues(); + console::log_1(&format!("after test eigenvalues").into());*/ + + 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::(time_res); + let run_time = performance.now() - start_time; + run_time_report.set(run_time); + + let canvas = display + .get::() + .unchecked_into::(); + let ctx = canvas + .get_context("2d") + .unwrap() + .unwrap() + .dyn_into::() + .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 + ) + } + } + }); +} \ No newline at end of file From 14fb6d01f0555ce0de9f43085f269a19051e8750 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 9 Aug 2024 15:18:13 -0700 Subject: [PATCH 6/7] Rust benchmark: tidy up a bit --- lang-trials/rust-benchmark/src/engine.rs | 170 +++++++++++------------ lang-trials/rust-benchmark/src/main.rs | 10 +- 2 files changed, 80 insertions(+), 100 deletions(-) diff --git a/lang-trials/rust-benchmark/src/engine.rs b/lang-trials/rust-benchmark/src/engine.rs index 3b2b290..a2661aa 100644 --- a/lang-trials/rust-benchmark/src/engine.rs +++ b/lang-trials/rust-benchmark/src/engine.rs @@ -1,10 +1,87 @@ use nalgebra::{*, allocator::Allocator}; use std::f64::consts::{PI, E}; -use web_sys::console; /*use std::ops::Sub;*/ /*use typenum::{B1, UInt, UTerm};*/ -/*pub fn eigvals_rotated(A: SMatrix, time: f64): complex_eigenvalues(&self) -> OVector, D>*/ +/* dynamic matrices */ +pub fn rand_eigval_series(time_res: usize) -> Vec, Dyn>> + where + N: ToTypenum + DimName + DimSub, + DefaultAllocator: + Allocator + + Allocator + + Allocator<>::Output> + + Allocator>::Output> +{ + // initialize the random matrix + let dim = N::try_to_usize().unwrap(); + let mut rand_mat = DMatrix::::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::::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::, 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(time_res: usize) -> Vec, Dyn>> + where + N: ToTypenum + DimName + DimSub, + DefaultAllocator: + Allocator + + Allocator + + Allocator<>::Output> + + Allocator>::Output> +{ + // initialize the random matrix + let dim = N::try_to_usize().unwrap(); + let mut rand_mat = DMatrix::::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::::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::, 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(time_res: usize) -> Vec, N>> @@ -18,7 +95,6 @@ use web_sys::console; { // initialize the random matrix let dim = N::try_to_usize().unwrap(); - console::log_1(&format!("dimension {dim}").into()); let mut rand_mat = OMatrix::::from_fn(|j, k| { let n = j*dim + k; E*((n*n) as f64) % 2.0 - 1.0 @@ -40,9 +116,7 @@ use web_sys::console; // find the eigenvalues let mut eigval_series = Vec::, N>>::with_capacity(time_res); - console::log_1(&"before engine eigenvalues".into()); eigval_series.push(rand_mat.complex_eigenvalues()); - console::log_1(&"after engine eigenvalues".into()); for _ in 1..time_res { rand_mat = &rot_step * rand_mat; eigval_series.push(rand_mat.complex_eigenvalues()); @@ -87,90 +161,4 @@ use web_sys::console; eigvals[t] = rand_mat.complex_eigenvalues(); } eigvals -}*/ - -/* dynamic matrices */ -pub fn rand_eigval_series(time_res: usize) -> Vec, Dyn>> - where - N: ToTypenum + DimName + DimSub, - DefaultAllocator: - Allocator + - Allocator + - Allocator<>::Output> + - Allocator>::Output> -{ - // initialize the random matrix - let dim = N::try_to_usize().unwrap(); - console::log_1(&format!("dimension {dim}").into()); - let mut rand_mat = DMatrix::::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::::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::, Dyn>>::with_capacity(time_res); - console::log_1(&"before engine eigenvalues".into()); - eigval_series.push(rand_mat.complex_eigenvalues()); - console::log_1(&"after engine eigenvalues".into()); - 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(time_res: usize) -> Vec, Dyn>> - where - N: ToTypenum + DimName + DimSub, - DefaultAllocator: - Allocator + - Allocator + - Allocator<>::Output> + - Allocator>::Output> -{ - // initialize the random matrix - let dim = N::try_to_usize().unwrap(); - console::log_1(&format!("dimension {dim}").into()); - let mut rand_mat = DMatrix::::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::::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::, Dyn>>::with_capacity(time_res); - console::log_1(&"before engine eigenvalues".into()); - eigval_series.push(rand_mat.complex_eigenvalues()); - console::log_1(&"after engine eigenvalues".into()); - for _ in 1..time_res { - rand_mat = &rot_step * rand_mat; - eigval_series.push(rand_mat.complex_eigenvalues()); - } - eigval_series }*/ \ No newline at end of file diff --git a/lang-trials/rust-benchmark/src/main.rs b/lang-trials/rust-benchmark/src/main.rs index 7143e20..9662dd7 100644 --- a/lang-trials/rust-benchmark/src/main.rs +++ b/lang-trials/rust-benchmark/src/main.rs @@ -1,7 +1,7 @@ use nalgebra::*; use std::f64::consts::PI as PI; use sycamore::{prelude::*, rt::{JsCast, JsValue}}; -use web_sys::{console, window}; +use web_sys::window; mod engine; @@ -10,14 +10,6 @@ fn main() { #[cfg(feature = "console_error_panic_hook")] console_error_panic_hook::set_once(); - /*console::log_1(&"before test schur 60".into());*/ - /*let test_rand_mat = OMatrix::::identity();*/ - /*let test_rot_step = OMatrix::::identity();*/ - /*let test_schur = test_rand_mat.schur(); - console::log_1(&format!("after test schur").into()); - let test_eigvals = test_schur.complex_eigenvalues(); - console::log_1(&format!("after test eigenvalues").into());*/ - sycamore::render(|| { let time_res: usize = 100; let time_step = create_signal(0.0); From 3665351e1222a9e53ccf43da5acefc99ace0f164 Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Fri, 9 Aug 2024 15:19:48 -0700 Subject: [PATCH 7/7] Scala benchmark: adjust interface code to match Rust --- lang-trials/scala-benchmark/main.css | 1 + .../src/main/scala/CircularLawApp.scala | 20 +++++++++---------- lang-trials/scala/main.css | 5 ----- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/lang-trials/scala-benchmark/main.css b/lang-trials/scala-benchmark/main.css index a89c3bc..f79e62c 100644 --- a/lang-trials/scala-benchmark/main.css +++ b/lang-trials/scala-benchmark/main.css @@ -15,6 +15,7 @@ canvas { float: left; background-color: #020202; border-radius: 10px; + margin-top: 5px; } input { diff --git a/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala b/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala index 2f74cd3..950e661 100644 --- a/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala +++ b/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala @@ -10,10 +10,10 @@ object CircularLawApp: val canvas = canvasTag(widthAttr := 600, heightAttr := 600) val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D] - val (eigvalSeries, runTimeReport) = randomEigvalSeries[60]() - val timeVar = Var("0") + val (eigvalSeries, runTimeReport) = randEigvalSeries[60]() + val timeStepState = Var("0") - def draw(timeStr: String): Unit = + def draw(timeStep: String): Unit = // center and normalize the coordinate system val width = canvas.ref.width val height = canvas.ref.height @@ -27,7 +27,7 @@ object CircularLawApp: val res = width / (2*rDisp) // draw the eigenvalues - val eigvals = eigvalSeries(timeStr.toInt) + val eigvals = eigvalSeries(timeStep.toInt) for n <- 0 to eigvals(0).length-1 do ctx.beginPath() ctx.arc( @@ -58,7 +58,7 @@ object CircularLawApp: eigen.imaginaryEigenvalues.asInstanceOf[NArray[Double]] ) - def randomEigvalSeries[N <: Int]()(using ValueOf[N]): (List[(NArray[Double], NArray[Double])], String) = + 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() @@ -66,8 +66,7 @@ object CircularLawApp: 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 endTime = System.currentTimeMillis() - val runTime = endTime - startTime + val runTime = System.currentTimeMillis() - startTime (series, runTime.toString() + " ms") def main(args: Array[String]): Unit = @@ -79,13 +78,12 @@ object CircularLawApp: canvas, input( typ := "range", - minAttr := "0", maxAttr := (eigvalSeries.length-1).toString, controlled( - value <-- timeVar.signal, - onInput.mapToValue --> timeVar.writer + value <-- timeStepState.signal, + onInput.mapToValue --> timeStepState.writer ), - timeVar.signal --> draw + timeStepState.signal --> draw ) ) renderOnDomContentLoaded(document.body, app) diff --git a/lang-trials/scala/main.css b/lang-trials/scala/main.css index ea89d47..3aedb99 100644 --- a/lang-trials/scala/main.css +++ b/lang-trials/scala/main.css @@ -38,11 +38,6 @@ input.point-3 { text-align: center; } -#result-display { - margin-top: 10px; - font-weight: bold; -} - canvas { float: left; background-color: #020202;