dyna3/app-proto/src/add_remove.rs

240 lines
8.6 KiB
Rust
Raw Normal View History

use sycamore::prelude::*;
use web_sys::{console, wasm_bindgen::JsValue};
use crate::{engine, AppState, assembly::{Assembly, Constraint, Element}};
/* DEBUG */
// load an example assembly for testing. this code will be removed once we've
// built a more formal test assembly system
fn load_gen_assemb(assembly: &Assembly) {
let _ = assembly.try_insert_element(
Element::new(
String::from("gemini_a"),
String::from("Castor"),
[1.00_f32, 0.25_f32, 0.00_f32],
engine::sphere(0.5, 0.5, 0.0, 1.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
String::from("gemini_b"),
String::from("Pollux"),
[0.00_f32, 0.25_f32, 1.00_f32],
engine::sphere(-0.5, -0.5, 0.0, 1.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
String::from("ursa_major"),
String::from("Ursa major"),
[0.25_f32, 0.00_f32, 1.00_f32],
engine::sphere(-0.5, 0.5, 0.0, 0.75)
)
);
let _ = assembly.try_insert_element(
Element::new(
String::from("ursa_minor"),
String::from("Ursa minor"),
[0.25_f32, 1.00_f32, 0.00_f32],
engine::sphere(0.5, -0.5, 0.0, 0.5)
)
);
let _ = assembly.try_insert_element(
Element::new(
String::from("moon_deimos"),
String::from("Deimos"),
[0.75_f32, 0.75_f32, 0.00_f32],
engine::sphere(0.0, 0.15, 1.0, 0.25)
)
);
let _ = assembly.try_insert_element(
Element::new(
String::from("moon_phobos"),
String::from("Phobos"),
[0.00_f32, 0.75_f32, 0.50_f32],
engine::sphere(0.0, -0.15, -1.0, 0.25)
)
);
}
/* DEBUG */
// load an example assembly for testing. this code will be removed once we've
// built a more formal test assembly system
fn load_low_curv_assemb(assembly: &Assembly) {
let a = 0.75_f64.sqrt();
let _ = assembly.try_insert_element(
Element::new(
"central".to_string(),
"Central".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32],
engine::sphere(0.0, 0.0, 0.0, 1.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
"assemb_plane".to_string(),
"Assembly plane".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32],
engine::sphere_with_offset(0.0, 0.0, 1.0, 0.0, 0.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
"side1".to_string(),
"Side 1".to_string(),
[1.00_f32, 0.00_f32, 0.25_f32],
engine::sphere_with_offset(1.0, 0.0, 0.0, 1.0, 0.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
"side2".to_string(),
"Side 2".to_string(),
[0.25_f32, 1.00_f32, 0.00_f32],
engine::sphere_with_offset(-0.5, a, 0.0, 1.0, 0.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
"side3".to_string(),
"Side 3".to_string(),
[0.00_f32, 0.25_f32, 1.00_f32],
engine::sphere_with_offset(-0.5, -a, 0.0, 1.0, 0.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
"corner1".to_string(),
"Corner 1".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32],
engine::sphere(-4.0/3.0, 0.0, 0.0, 1.0/3.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
"corner2".to_string(),
"Corner 2".to_string(),
[0.75_f32, 0.75_f32, 0.75_f32],
engine::sphere(2.0/3.0, -4.0/3.0 * a, 0.0, 1.0/3.0)
)
);
let _ = assembly.try_insert_element(
Element::new(
String::from("corner3"),
String::from("Corner 3"),
[0.75_f32, 0.75_f32, 0.75_f32],
engine::sphere(2.0/3.0, 4.0/3.0 * a, 0.0, 1.0/3.0)
)
);
}
#[component]
pub fn AddRemove() -> View {
/* DEBUG */
let assembly_name = create_signal("general".to_string());
create_effect(move || {
// get name of chosen assembly
let name = assembly_name.get_clone();
console::log_1(
&JsValue::from(format!("Showing assembly \"{}\"", name.clone()))
);
batch(|| {
let state = use_context::<AppState>();
let assembly = &state.assembly;
// clear state
assembly.elements.update(|elts| elts.clear());
assembly.elements_by_id.update(|elts_by_id| elts_by_id.clear());
state.selection.update(|sel| sel.clear());
// load assembly
match name.as_str() {
"general" => load_gen_assemb(assembly),
"low-curv" => load_low_curv_assemb(assembly),
_ => ()
};
});
});
view! {
div(id="add-remove") {
button(
on:click=|_| {
let state = use_context::<AppState>();
state.assembly.insert_new_element();
/* DEBUG */
// print updated list of elements by identifier
console::log_1(&JsValue::from("elements by identifier:"));
for (id, key) in state.assembly.elements_by_id.get_clone().iter() {
console::log_3(
&JsValue::from(" "),
&JsValue::from(id),
&JsValue::from(*key)
);
}
}
) { "+" }
button(
class="emoji", /* KLUDGE */ // for convenience, we're using an emoji as a temporary icon for this button
disabled={
let state = use_context::<AppState>();
state.selection.with(|sel| sel.len() != 2)
},
on:click=|_| {
let state = use_context::<AppState>();
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
let subjects = state.selection.with(
|sel| {
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
let subject_vec: Vec<_> = sel.into_iter().collect();
(subject_vec[0].clone(), subject_vec[1].clone())
}
);
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
let lorentz_prod = create_signal(0.0);
let lorentz_prod_valid = create_signal(false);
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
let active = create_signal(true);
state.assembly.insert_constraint(Constraint {
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
subjects: subjects,
lorentz_prod: lorentz_prod,
lorentz_prod_text: create_signal(String::new()),
lorentz_prod_valid: lorentz_prod_valid,
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
active: active,
});
state.selection.update(|sel| sel.clear());
/* DEBUG */
// print updated constraint list
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
console::log_1(&JsValue::from("Constraints:"));
state.assembly.constraints.with(|csts| {
for (_, cst) in csts.into_iter() {
console::log_5(
&JsValue::from(" "),
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
&JsValue::from(cst.subjects.0),
&JsValue::from(cst.subjects.1),
&JsValue::from(":"),
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
&JsValue::from(cst.lorentz_prod.get_untracked())
);
}
});
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
// update the realization when the constraint becomes active
// and valid, or is edited while active and valid
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
create_effect(move || {
console::log_1(&JsValue::from(
format!("Constraint ({}, {}) updated", subjects.0, subjects.1)
));
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
lorentz_prod.track();
if active.get() && lorentz_prod_valid.get() {
Integrate engine into application prototype (#15) Port the engine prototype to Rust, integrate it into the application prototype, and use it to enforce the constraints. ### Features To see the engine in action: 1. Add a constraint by shift-clicking to select two spheres in the outline view and then hitting the 🔗 button 2. Click a summary arrow to see the outline item for the new constraint 2. Set the constraint's Lorentz product by entering a value in the text field at the right end of the outline item * *The display should update as soon as you press* Enter *or focus away from the text field* The checkbox at the left end of a constraint outline item controls whether the constraint is active. Activating a constraint triggers a solution update. (Deactivating a constraint doesn't, since the remaining active constraints are still satisfied.) ### Precision The Julia prototype of the engine uses a generic scalar type, so you can pass in any type the linear algebra functions are implemented for. The examples use the [adjustable-precision](https://docs.julialang.org/en/v1/base/numbers/#Base.MPFR.setprecision) `BigFloat` type. In the Rust port of the engine, the scalar type is currently fixed at `f64`. Switching to generic scalars shouldn't be too hard, but I haven't looked into [which other types](https://www.nalgebra.org/docs/user_guide/generic_programming) the linear algebra functions are implemented for. ### Testing To confirm quantitatively that the Rust port of the engine is working, you can go to the `app-proto` folder and: * Run some automated tests by calling `cargo test`. * Inspect the optimization process in a few examples calling the `run-examples` script. The first example that prints is the same as the Irisawa hexlet example from the engine prototype. If you go into `engine-proto/gram-test`, launch Julia, and then ``` include("irisawa-hexlet.jl") for (step, scaled_loss) in enumerate(history_alt.scaled_loss) println(rpad(step-1, 4), " | ", scaled_loss) 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. ### A small engine revision The Rust port of the engine improves on the Julia prototype in one part of the constraint-solving routine: projecting the Hessian onto the subspace where the frozen entries stay constant. The Julia prototype does this by removing the rows and columns of the Hessian that correspond to the frozen entries, finding the Newton step from the resulting "compressed" Hessian, and then adding zero entries to the Newton step in the appropriate places. The Rust port instead replaces each frozen row and column with its corresponding standard unit vector, avoiding the finicky compressing and decompressing steps. To confirm that this version of the constraint-solving routine works the same as the original, I implemented it in Julia as `realize_gram_alt_proj`. The solutions we get from this routine match the ones we get from the original `realize_gram` to very high precision, and in the simplest examples (`sphere-in-tetrahedron.jl` and `tetrahedron-radius-ratio.jl`), the descent paths also match to very high precision. In a more complicated example (`irisawa-hexlet.jl`), the descent paths diverge about a quarter of the way into the search, even though they end up in the same place. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: https://code.studioinfinity.org/glen/dyna3/pulls/15 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
2024-11-12 00:46:16 +00:00
state.assembly.realize();
}
});
}
) { "🔗" }
select(bind:value=assembly_name) { /* DEBUG */ // example assembly chooser
option(value="general") { "General" }
option(value="low-curv") { "Low-curvature" }
option(value="empty") { "Empty" }
}
}
}
}