diff --git a/README.md b/README.md index cf3e589..3a29eb0 100644 --- a/README.md +++ b/README.md @@ -25,37 +25,32 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter ### Install the prerequisites 1. Install [`rustup`](https://rust-lang.github.io/rustup/): the officially recommended Rust toolchain manager - - It's available on Ubuntu as a [Snap](https://snapcraft.io/rustup) + * It's available on Ubuntu as a [Snap](https://snapcraft.io/rustup) 2. Call `rustup default stable` to "download the latest stable release of Rust and set it as your default toolchain" - - If you forget, the `rustup` [help system](https://github.com/rust-lang/rustup/blob/d9b3601c3feb2e88cf3f8ca4f7ab4fdad71441fd/src/errors.rs#L109-L112) will remind you + * If you forget, the `rustup` [help system](https://github.com/rust-lang/rustup/blob/d9b3601c3feb2e88cf3f8ca4f7ab4fdad71441fd/src/errors.rs#L109-L112) will remind you 3. Call `rustup target add wasm32-unknown-unknown` to add the [most generic 32-bit WebAssembly target](https://doc.rust-lang.org/nightly/rustc/platform-support/wasm32-unknown-unknown.html) 4. Call `cargo install wasm-pack` to install the [WebAssembly toolchain](https://rustwasm.github.io/docs/wasm-pack/) 5. Call `cargo install trunk` to install the [Trunk](https://trunkrs.dev/) web-build tool 6. Add the `.cargo/bin` folder in your home directory to your executable search path - - This lets you call Trunk, and other tools installed by Cargo, without specifying their paths - - On POSIX systems, the search path is stored in the `PATH` environment variable + * This lets you call Trunk, and other tools installed by Cargo, without specifying their paths + * On POSIX systems, the search path is stored in the `PATH` environment variable ### Play with the prototype 1. From the `app-proto` folder, call `trunk serve --release` to build and serve the prototype - - The crates the prototype depends on will be downloaded and served automatically - - For a faster build, at the expense of a much slower prototype, you can call `trunk serve` without the `--release` flag - - If you want to stay in the top-level folder, you can call `trunk serve --config app-proto [--release]` from there instead. + * *The crates the prototype depends on will be downloaded and served automatically* + * *For a faster build, at the expense of a much slower prototype, you can call `trunk serve` without the `--release` flag* + * *If you want to stay in the top-level folder, you can call `trunk serve --config app-proto [--release]`* from there instead. 3. In a web browser, visit one of the URLs listed under the message `INFO 📡 server listening at:` - - Touching any file in the `app-proto` folder will make Trunk rebuild and live-reload the prototype + * *Touching any file in the `app-proto` folder will make Trunk rebuild and live-reload the prototype* 4. Press *ctrl+C* in the shell where Trunk is running to stop serving the prototype ### Run the engine on some example problems -1. Use `sh` to run the script `tools/run-examples.sh` - - The script is location-independent, so you can do this from anywhere in the dyna3 repository - - The call from the top level of the repository is: - - ```bash - sh tools/run-examples.sh - ``` - - For each example problem, the engine will print the value of the loss function at each optimization step - - The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then +1. Go into the `app-proto` folder +2. Call `./run-examples` + * *For each example problem, the engine will print the value of the loss function at each optimization step* + * *The first example that prints is the same as the Irisawa hexlet example from the Julia version of the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then* ```julia include("irisawa-hexlet.jl") @@ -64,24 +59,9 @@ The latest prototype is in the folder `app-proto`. It includes both a user inter end ``` - you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show + *you should see that it prints basically the same loss history until the last few steps, when the lower default precision of the Rust engine really starts to show* ### Run the automated tests 1. Go into the `app-proto` folder 2. Call `cargo test` - -### Deploy the prototype - -1. From the `app-proto` folder, call `trunk build --release` - - Building in [release mode](https://doc.rust-lang.org/cargo/reference/profiles.html#release) produces an executable which is smaller and often much faster, but harder to debug and more time-consuming to build - - If you want to stay in the top-level folder, you can call `trunk build --config app-proto --release` from there instead -2. Use `sh` to run the packaging script `tools/package-for-deployment.sh`. - - The script is location-independent, so you can do this from anywhere in the dyna3 repository - - The call from the top level of the repository is: - ```bash - sh tools/package-for-deployment.sh - ``` - - This will overwrite or replace the files in `deploy/dyna3` -3. Put the contents of `deploy/dyna3` in the folder on your server that the prototype will be served from. - - To simplify uploading, you might want to combine these files into an archive called `deploy/dyna3.zip`. Git has been set to ignore this path \ No newline at end of file diff --git a/app-proto/Trunk.toml b/app-proto/Trunk.toml deleted file mode 100644 index 017deba..0000000 --- a/app-proto/Trunk.toml +++ /dev/null @@ -1,2 +0,0 @@ -[build] -public_url = "./" \ No newline at end of file diff --git a/tools/run-examples.sh b/app-proto/run-examples.sh similarity index 89% rename from tools/run-examples.sh rename to app-proto/run-examples.sh index 0946d92..861addf 100644 --- a/tools/run-examples.sh +++ b/app-proto/run-examples.sh @@ -8,7 +8,7 @@ # the application prototype # find the manifest file for the application prototype -MANIFEST="$(dirname -- $0)/../app-proto/Cargo.toml" +MANIFEST="$(dirname -- $0)/Cargo.toml" # set up the command that runs each example RUN_EXAMPLE="cargo run --manifest-path $MANIFEST --example" diff --git a/app-proto/src/assembly.rs b/app-proto/src/assembly.rs index 94e7b3c..43066fd 100644 --- a/app-proto/src/assembly.rs +++ b/app-proto/src/assembly.rs @@ -175,8 +175,8 @@ impl Sphere { label: String, color: ElementColor, representation: DVector, - ) -> Self { - Self { + ) -> Sphere { + Sphere { id, label, color, @@ -194,8 +194,8 @@ impl Element for Sphere { "sphere".to_string() } - fn default(id: String, id_num: u64) -> Self { - Self::new( + fn default(id: String, id_num: u64) -> Sphere { + Sphere::new( id, format!("Sphere {id_num}"), [0.75_f32, 0.75_f32, 0.75_f32], @@ -275,8 +275,8 @@ impl Point { label: String, color: ElementColor, representation: DVector, - ) -> Self { - Self { + ) -> Point { + Point { id, label, color, @@ -294,8 +294,8 @@ impl Element for Point { "point".to_string() } - fn default(id: String, id_num: u64) -> Self { - Self::new( + fn default(id: String, id_num: u64) -> Point { + Point::new( id, format!("Point {id_num}"), [0.75_f32, 0.75_f32, 0.75_f32], @@ -348,7 +348,7 @@ impl ProblemPoser for Point { format!("Point \"{}\" should be indexed before writing problem data", self.id).as_str() ); problem.gram.push_sym(index, index, 0.0); - problem.frozen.push(Self::WEIGHT_COMPONENT, index, 0.5); + problem.frozen.push(Point::WEIGHT_COMPONENT, index, 0.5); problem.guess.set_column(index, &self.representation.get_clone_untracked()); } } @@ -393,7 +393,7 @@ pub struct InversiveDistanceRegulator { } impl InversiveDistanceRegulator { - pub fn new(subjects: [Rc; 2]) -> Self { + pub fn new(subjects: [Rc; 2]) -> InversiveDistanceRegulator { let representations = subjects.each_ref().map(|subj| subj.representation()); let measurement = create_memo(move || { representations[0].with(|rep_0| @@ -406,7 +406,7 @@ impl InversiveDistanceRegulator { let set_point = create_signal(SpecifiedValue::from_empty_spec()); let serial = Self::next_serial(); - Self { subjects, measurement, set_point, serial } + InversiveDistanceRegulator { subjects, measurement, set_point, serial } } } @@ -453,7 +453,7 @@ pub struct HalfCurvatureRegulator { } impl HalfCurvatureRegulator { - pub fn new(subject: Rc) -> Self { + pub fn new(subject: Rc) -> HalfCurvatureRegulator { let measurement = subject.representation().map( |rep| rep[Sphere::CURVATURE_COMPONENT] ); @@ -461,7 +461,7 @@ impl HalfCurvatureRegulator { let set_point = create_signal(SpecifiedValue::from_empty_spec()); let serial = Self::next_serial(); - Self { subject, measurement, set_point, serial } + HalfCurvatureRegulator { subject, measurement, set_point, serial } } } diff --git a/app-proto/src/components/diagnostics.rs b/app-proto/src/components/diagnostics.rs index e265982..b274dca 100644 --- a/app-proto/src/components/diagnostics.rs +++ b/app-proto/src/components/diagnostics.rs @@ -15,8 +15,8 @@ struct DiagnosticsState { } impl DiagnosticsState { - fn new(initial_tab: String) -> Self { - Self { active_tab: create_signal(initial_tab) } + fn new(initial_tab: String) -> DiagnosticsState { + DiagnosticsState { active_tab: create_signal(initial_tab) } } } diff --git a/app-proto/src/components/display.rs b/app-proto/src/components/display.rs index da921dd..a0cdba6 100644 --- a/app-proto/src/components/display.rs +++ b/app-proto/src/components/display.rs @@ -41,8 +41,8 @@ struct SceneSpheres { } impl SceneSpheres { - fn new() -> Self { - Self { + fn new() -> SceneSpheres { + SceneSpheres { representations: Vec::new(), colors_with_opacity: Vec::new(), highlights: Vec::new(), @@ -71,8 +71,8 @@ struct ScenePoints { } impl ScenePoints { - fn new() -> Self { - Self { + fn new() -> ScenePoints { + ScenePoints { representations: Vec::new(), colors_with_opacity: Vec::new(), highlights: Vec::new(), @@ -97,8 +97,8 @@ pub struct Scene { } impl Scene { - fn new() -> Self { - Self { + fn new() -> Scene { + Scene { spheres: SceneSpheres::new(), points: ScenePoints::new(), } diff --git a/app-proto/src/components/test_assembly_chooser.rs b/app-proto/src/components/test_assembly_chooser.rs index 0d387d3..5ed94ad 100644 --- a/app-proto/src/components/test_assembly_chooser.rs +++ b/app-proto/src/components/test_assembly_chooser.rs @@ -26,7 +26,7 @@ use crate::{ // done more work on saving and loading assemblies, we should come back to this // code to see if it can be simplified -fn load_general(assembly: &Assembly) { +fn load_gen_assemb(assembly: &Assembly) { let _ = assembly.try_insert_element( Sphere::new( String::from("gemini_a"), @@ -77,7 +77,7 @@ fn load_general(assembly: &Assembly) { ); } -fn load_low_curvature(assembly: &Assembly) { +fn load_low_curv_assemb(assembly: &Assembly) { // create the spheres let a = 0.75_f64.sqrt(); let _ = assembly.try_insert_element( @@ -196,7 +196,7 @@ fn load_low_curvature(assembly: &Assembly) { } } -fn load_pointed(assembly: &Assembly) { +fn load_pointed_assemb(assembly: &Assembly) { let _ = assembly.try_insert_element( Point::new( format!("point_front"), @@ -246,7 +246,7 @@ fn load_pointed(assembly: &Assembly) { // B-C " // C-C " // A-C -0.25 * φ^2 = -0.6545084971874737 -fn load_tridiminished_icosahedron(assembly: &Assembly) { +fn load_tridim_icosahedron_assemb(assembly: &Assembly) { // create the vertices const COLOR_A: ElementColor = [1.00_f32, 0.25_f32, 0.25_f32]; const COLOR_B: ElementColor = [0.75_f32, 0.75_f32, 0.75_f32]; @@ -409,7 +409,7 @@ fn load_tridiminished_icosahedron(assembly: &Assembly) { // to finish describing the dodecahedral circle packing, set the inversive // distance regulators to -1. some of the regulators have already been set -fn load_dodecahedral_packing(assembly: &Assembly) { +fn load_dodeca_packing_assemb(assembly: &Assembly) { // add the substrate let _ = assembly.try_insert_element( Sphere::new( @@ -550,7 +550,7 @@ fn load_dodecahedral_packing(assembly: &Assembly) { // the initial configuration of this test assembly deliberately violates the // constraints, so loading the assembly will trigger a non-trivial realization -fn load_balanced(assembly: &Assembly) { +fn load_balanced_assemb(assembly: &Assembly) { // create the spheres const R_OUTER: f64 = 10.0; const R_INNER: f64 = 4.0; @@ -611,7 +611,7 @@ fn load_balanced(assembly: &Assembly) { // the initial configuration of this test assembly deliberately violates the // constraints, so loading the assembly will trigger a non-trivial realization -fn load_off_center(assembly: &Assembly) { +fn load_off_center_assemb(assembly: &Assembly) { // create a point almost at the origin and a sphere centered on the origin let _ = assembly.try_insert_element( Point::new( @@ -648,7 +648,7 @@ fn load_off_center(assembly: &Assembly) { // sqrt(1/6) and sqrt(3/2), respectively. to measure those radii, set an // inversive distance of -1 between the insphere and each face, and then set an // inversive distance of 0 between the circumsphere and each vertex -fn load_radius_ratio(assembly: &Assembly) { +fn load_radius_ratio_assemb(assembly: &Assembly) { let index_range = 1..=4; // create the spheres @@ -789,7 +789,7 @@ fn load_radius_ratio(assembly: &Assembly) { // conditions are exactly representable as floats, unlike the analogous numbers // in the scaled-up problem. the inexact representations might break the // symmetry that's getting the engine stuck -fn load_irisawa_hexlet(assembly: &Assembly) { +fn load_irisawa_hexlet_assemb(assembly: &Assembly) { let index_range = 1..=6; let colors = [ [1.00_f32, 0.00_f32, 0.25_f32], @@ -909,15 +909,15 @@ pub fn TestAssemblyChooser() -> View { // load assembly match name.as_str() { - "general" => load_general(assembly), - "low-curvature" => load_low_curvature(assembly), - "pointed" => load_pointed(assembly), - "tridiminished-icosahedron" => load_tridiminished_icosahedron(assembly), - "dodecahedral-packing" => load_dodecahedral_packing(assembly), - "balanced" => load_balanced(assembly), - "off-center" => load_off_center(assembly), - "radius-ratio" => load_radius_ratio(assembly), - "irisawa-hexlet" => load_irisawa_hexlet(assembly), + "general" => load_gen_assemb(assembly), + "low-curv" => load_low_curv_assemb(assembly), + "pointed" => load_pointed_assemb(assembly), + "tridim-icosahedron" => load_tridim_icosahedron_assemb(assembly), + "dodeca-packing" => load_dodeca_packing_assemb(assembly), + "balanced" => load_balanced_assemb(assembly), + "off-center" => load_off_center_assemb(assembly), + "radius-ratio" => load_radius_ratio_assemb(assembly), + "irisawa-hexlet" => load_irisawa_hexlet_assemb(assembly), _ => (), }; }); @@ -927,10 +927,10 @@ pub fn TestAssemblyChooser() -> View { view! { select(bind:value = assembly_name) { option(value = "general") { "General" } - option(value = "low-curvature") { "Low-curvature" } + option(value = "low-curv") { "Low-curvature" } option(value = "pointed") { "Pointed" } - option(value = "tridiminished-icosahedron") { "Tridiminished icosahedron" } - option(value = "dodecahedral-packing") { "Dodecahedral packing" } + option(value = "tridim-icosahedron") { "Tridiminished icosahedron" } + option(value = "dodeca-packing") { "Dodecahedral packing" } option(value = "balanced") { "Balanced" } option(value = "off-center") { "Off-center" } option(value = "radius-ratio") { "Radius ratio" } diff --git a/app-proto/src/engine.rs b/app-proto/src/engine.rs index d033c01..dc6b470 100644 --- a/app-proto/src/engine.rs +++ b/app-proto/src/engine.rs @@ -59,12 +59,12 @@ pub struct MatrixEntry { pub struct PartialMatrix(Vec); impl PartialMatrix { - pub fn new() -> Self { - Self(Vec::::new()) + pub fn new() -> PartialMatrix { + PartialMatrix(Vec::::new()) } pub fn push(&mut self, row: usize, col: usize, value: f64) { - let Self(entries) = self; + let PartialMatrix(entries) = self; entries.push(MatrixEntry { index: (row, col), value }); } @@ -114,7 +114,7 @@ impl IntoIterator for PartialMatrix { type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - let Self(entries) = self; + let PartialMatrix(entries) = self; entries.into_iter() } } @@ -139,8 +139,8 @@ pub struct ConfigSubspace { } impl ConfigSubspace { - pub fn zero(assembly_dim: usize) -> Self { - Self { + pub fn zero(assembly_dim: usize) -> ConfigSubspace { + ConfigSubspace { assembly_dim, basis_proj: Vec::new(), basis_std: Vec::new(), @@ -154,7 +154,7 @@ impl ConfigSubspace { a: DMatrix, proj_to_std: DMatrix, assembly_dim: usize, - ) -> Self { + ) -> ConfigSubspace { // find a basis for the kernel. the basis is expressed in the projection // coordinates, and it's orthonormal with respect to the projection // inner product @@ -173,7 +173,7 @@ impl ConfigSubspace { const ELEMENT_DIM: usize = 5; const UNIFORM_DIM: usize = 4; - Self { + ConfigSubspace { assembly_dim, basis_std: basis_std.column_iter().map( |v| Into::>::into( @@ -224,8 +224,8 @@ pub struct DescentHistory { } impl DescentHistory { - pub fn new() -> Self { - Self { + pub fn new() -> DescentHistory { + DescentHistory { config: Vec::>::new(), scaled_loss: Vec::::new(), neg_grad: Vec::>::new(), @@ -245,9 +245,9 @@ pub struct ConstraintProblem { } impl ConstraintProblem { - pub fn new(element_count: usize) -> Self { + pub fn new(element_count: usize) -> ConstraintProblem { const ELEMENT_DIM: usize = 5; - Self { + ConstraintProblem { gram: PartialMatrix::new(), frozen: PartialMatrix::new(), guess: DMatrix::::zeros(ELEMENT_DIM, element_count), @@ -255,8 +255,8 @@ impl ConstraintProblem { } #[cfg(feature = "dev")] - pub fn from_guess(guess_columns: &[DVector]) -> Self { - Self { + pub fn from_guess(guess_columns: &[DVector]) -> ConstraintProblem { + ConstraintProblem { gram: PartialMatrix::new(), frozen: PartialMatrix::new(), guess: DMatrix::from_columns(guess_columns), @@ -284,10 +284,10 @@ struct SearchState { } impl SearchState { - fn from_config(gram: &PartialMatrix, config: DMatrix) -> Self { + fn from_config(gram: &PartialMatrix, config: DMatrix) -> SearchState { let err_proj = gram.sub_proj(&(config.tr_mul(&*Q) * &config)); let loss = err_proj.norm_squared(); - Self { config, err_proj, loss } + SearchState { config, err_proj, loss } } } diff --git a/app-proto/src/main.rs b/app-proto/src/main.rs index a03b026..7ca0731 100644 --- a/app-proto/src/main.rs +++ b/app-proto/src/main.rs @@ -24,8 +24,8 @@ struct AppState { } impl AppState { - fn new() -> Self { - Self { + fn new() -> AppState { + AppState { assembly: Assembly::new(), selection: create_signal(BTreeSet::default()), } diff --git a/app-proto/src/specified.rs b/app-proto/src/specified.rs index 788460b..ea1731c 100644 --- a/app-proto/src/specified.rs +++ b/app-proto/src/specified.rs @@ -17,8 +17,8 @@ pub struct SpecifiedValue { } impl SpecifiedValue { - pub fn from_empty_spec() -> Self { - Self { spec: String::new(), value: None } + pub fn from_empty_spec() -> SpecifiedValue { + SpecifiedValue { spec: String::new(), value: None } } pub fn is_present(&self) -> bool { @@ -34,10 +34,10 @@ impl TryFrom for SpecifiedValue { fn try_from(spec: String) -> Result { if spec.is_empty() { - Ok(Self::from_empty_spec()) + Ok(SpecifiedValue::from_empty_spec()) } else { spec.parse::().map( - |value| Self { spec, value: Some(value) } + |value| SpecifiedValue { spec, value: Some(value) } ) } } diff --git a/deploy/.gitignore b/deploy/.gitignore deleted file mode 100644 index 192f529..0000000 --- a/deploy/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/dyna3.zip -/dyna3/index.html -/dyna3/dyna3-*.js -/dyna3/dyna3-*.wasm -/dyna3/main-*.css \ No newline at end of file diff --git a/tools/package-for-deployment.sh b/tools/package-for-deployment.sh deleted file mode 100644 index fdda434..0000000 --- a/tools/package-for-deployment.sh +++ /dev/null @@ -1,16 +0,0 @@ -# set paths. this technique for getting the script location comes from -# `mklement0` on Stack Overflow -# -# https://stackoverflow.com/a/24114056 -# -TOOLS=$(dirname -- $0) -SRC="$TOOLS/../app-proto/dist" -DEST="$TOOLS/../deploy/dyna3" - -# remove the old hash-named files -[ -e "$DEST"/dyna3-*.js ] && rm "$DEST"/dyna3-*.js -[ -e "$DEST"/dyna3-*.wasm ] && rm "$DEST"/dyna3-*.wasm -[ -e "$DEST"/main-*.css ] && rm "$DEST"/main-*.css - -# copy the distribution -cp -r "$SRC/." "$DEST"