forked from StudioInfinity/dyna3
feat: Engine diagnostics (#92)
Adds a `Diagnostics` component that shows the following diagnostics from the last realization: - Confirmation of success or a short description of what failed. - The value of the loss function at each step. - The spectrum of the Hessian at each step. The loss and spectrum plots are shown on switchable panels. Also includes some refactoring/renaming of existing code. Co-authored-by: Aaron Fenyes <aaron.fenyes@fareycircles.ooo> Reviewed-on: StudioInfinity/dyna3#92 Co-authored-by: Vectornaut <vectornaut@nobody@nowhere.net> Co-committed-by: Vectornaut <vectornaut@nobody@nowhere.net>
This commit is contained in:
parent
4cb3262555
commit
5864017e6f
17 changed files with 1120 additions and 150 deletions
36
app-proto/examples/common/print.rs
Normal file
36
app-proto/examples/common/print.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use nalgebra::DMatrix;
|
||||
|
||||
use dyna3::engine::{Q, DescentHistory, Realization};
|
||||
|
||||
pub fn title(title: &str) {
|
||||
println!("─── {title} ───");
|
||||
}
|
||||
|
||||
pub fn realization_diagnostics(realization: &Realization) {
|
||||
let Realization { result, history } = realization;
|
||||
println!();
|
||||
if let Err(ref message) = result {
|
||||
println!("❌️ {message}");
|
||||
} else {
|
||||
println!("✅️ Target accuracy achieved!");
|
||||
}
|
||||
println!("Steps: {}", history.scaled_loss.len() - 1);
|
||||
println!("Loss: {}", history.scaled_loss.last().unwrap());
|
||||
}
|
||||
|
||||
pub fn gram_matrix(config: &DMatrix<f64>) {
|
||||
println!("\nCompleted Gram matrix:{}", (config.tr_mul(&*Q) * config).to_string().trim_end());
|
||||
}
|
||||
|
||||
pub fn config(config: &DMatrix<f64>) {
|
||||
println!("\nConfiguration:{}", config.to_string().trim_end());
|
||||
}
|
||||
|
||||
pub fn loss_history(history: &DescentHistory) {
|
||||
println!("\nStep │ Loss\n─────┼────────────────────────────────");
|
||||
for (step, scaled_loss) in history.scaled_loss.iter().enumerate() {
|
||||
println!("{:<4} │ {}", step, scaled_loss);
|
||||
}
|
||||
}
|
|
@ -1,25 +1,23 @@
|
|||
use dyna3::engine::{Q, examples::realize_irisawa_hexlet};
|
||||
#[path = "common/print.rs"]
|
||||
mod print;
|
||||
|
||||
use dyna3::engine::{ConfigNeighborhood, examples::realize_irisawa_hexlet};
|
||||
|
||||
fn main() {
|
||||
const SCALED_TOL: f64 = 1.0e-12;
|
||||
let (config, _, success, history) = realize_irisawa_hexlet(SCALED_TOL);
|
||||
print!("\nCompleted Gram matrix:{}", config.tr_mul(&*Q) * &config);
|
||||
if success {
|
||||
println!("Target accuracy achieved!");
|
||||
} else {
|
||||
println!("Failed to reach target accuracy");
|
||||
}
|
||||
println!("Steps: {}", history.scaled_loss.len() - 1);
|
||||
println!("Loss: {}", history.scaled_loss.last().unwrap());
|
||||
if success {
|
||||
let realization = realize_irisawa_hexlet(SCALED_TOL);
|
||||
print::title("Irisawa hexlet");
|
||||
print::realization_diagnostics(&realization);
|
||||
if let Ok(ConfigNeighborhood { config, .. }) = realization.result {
|
||||
// print the diameters of the chain spheres
|
||||
println!("\nChain diameters:");
|
||||
println!(" {} sun (given)", 1.0 / config[(3, 3)]);
|
||||
for k in 4..9 {
|
||||
println!(" {} sun", 1.0 / config[(3, k)]);
|
||||
}
|
||||
|
||||
// print the completed Gram matrix
|
||||
print::gram_matrix(&config);
|
||||
}
|
||||
println!("\nStep │ Loss\n─────┼────────────────────────────────");
|
||||
for (step, scaled_loss) in history.scaled_loss.into_iter().enumerate() {
|
||||
println!("{:<4} │ {}", step, scaled_loss);
|
||||
}
|
||||
print::loss_history(&realization.history);
|
||||
}
|
|
@ -1,30 +1,32 @@
|
|||
#[path = "common/print.rs"]
|
||||
mod print;
|
||||
|
||||
use nalgebra::{DMatrix, DVector};
|
||||
|
||||
use dyna3::engine::{Q, examples::realize_kaleidocycle};
|
||||
use dyna3::engine::{ConfigNeighborhood, examples::realize_kaleidocycle};
|
||||
|
||||
fn main() {
|
||||
const SCALED_TOL: f64 = 1.0e-12;
|
||||
let (config, tangent, success, history) = realize_kaleidocycle(SCALED_TOL);
|
||||
print!("Completed Gram matrix:{}", config.tr_mul(&*Q) * &config);
|
||||
print!("Configuration:{}", config);
|
||||
if success {
|
||||
println!("Target accuracy achieved!");
|
||||
} else {
|
||||
println!("Failed to reach target accuracy");
|
||||
let realization = realize_kaleidocycle(SCALED_TOL);
|
||||
print::title("Kaleidocycle");
|
||||
print::realization_diagnostics(&realization);
|
||||
if let Ok(ConfigNeighborhood { config, nbhd: tangent }) = realization.result {
|
||||
// print the completed Gram matrix and the realized configuration
|
||||
print::gram_matrix(&config);
|
||||
print::config(&config);
|
||||
|
||||
// find the kaleidocycle's twist motion by projecting onto the tangent
|
||||
// space
|
||||
const N_POINTS: usize = 12;
|
||||
let up = DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]);
|
||||
let down = -&up;
|
||||
let twist_motion: DMatrix<_> = (0..N_POINTS).step_by(4).flat_map(
|
||||
|n| [
|
||||
tangent.proj(&up.as_view(), n),
|
||||
tangent.proj(&down.as_view(), n+1)
|
||||
]
|
||||
).sum();
|
||||
let normalization = 5.0 / twist_motion[(2, 0)];
|
||||
println!("\nTwist motion:{}", (normalization * twist_motion).to_string().trim_end());
|
||||
}
|
||||
println!("Steps: {}", history.scaled_loss.len() - 1);
|
||||
println!("Loss: {}\n", history.scaled_loss.last().unwrap());
|
||||
|
||||
// find the kaleidocycle's twist motion by projecting onto the tangent space
|
||||
const N_POINTS: usize = 12;
|
||||
let up = DVector::from_column_slice(&[0.0, 0.0, 1.0, 0.0]);
|
||||
let down = -&up;
|
||||
let twist_motion: DMatrix<_> = (0..N_POINTS).step_by(4).flat_map(
|
||||
|n| [
|
||||
tangent.proj(&up.as_view(), n),
|
||||
tangent.proj(&down.as_view(), n+1)
|
||||
]
|
||||
).sum();
|
||||
let normalization = 5.0 / twist_motion[(2, 0)];
|
||||
print!("Twist motion:{}", normalization * twist_motion);
|
||||
}
|
|
@ -1,4 +1,13 @@
|
|||
use dyna3::engine::{Q, point, realize_gram, sphere, ConstraintProblem};
|
||||
#[path = "common/print.rs"]
|
||||
mod print;
|
||||
|
||||
use dyna3::engine::{
|
||||
point,
|
||||
realize_gram,
|
||||
sphere,
|
||||
ConfigNeighborhood,
|
||||
ConstraintProblem
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut problem = ConstraintProblem::from_guess(&[
|
||||
|
@ -11,21 +20,14 @@ fn main() {
|
|||
}
|
||||
}
|
||||
problem.frozen.push(3, 0, problem.guess[(3, 0)]);
|
||||
println!();
|
||||
let (config, _, success, history) = realize_gram(
|
||||
let realization = realize_gram(
|
||||
&problem, 1.0e-12, 0.5, 0.9, 1.1, 200, 110
|
||||
);
|
||||
print!("\nCompleted Gram matrix:{}", config.tr_mul(&*Q) * &config);
|
||||
print!("Configuration:{}", config);
|
||||
if success {
|
||||
println!("Target accuracy achieved!");
|
||||
} else {
|
||||
println!("Failed to reach target accuracy");
|
||||
}
|
||||
println!("Steps: {}", history.scaled_loss.len() - 1);
|
||||
println!("Loss: {}", history.scaled_loss.last().unwrap());
|
||||
println!("\nStep │ Loss\n─────┼────────────────────────────────");
|
||||
for (step, scaled_loss) in history.scaled_loss.into_iter().enumerate() {
|
||||
println!("{:<4} │ {}", step, scaled_loss);
|
||||
print::title("Point on a sphere");
|
||||
print::realization_diagnostics(&realization);
|
||||
if let Ok(ConfigNeighborhood{ config, .. }) = realization.result {
|
||||
print::gram_matrix(&config);
|
||||
print::config(&config);
|
||||
}
|
||||
print::loss_history(&realization.history);
|
||||
}
|
|
@ -1,4 +1,12 @@
|
|||
use dyna3::engine::{Q, realize_gram, sphere, ConstraintProblem};
|
||||
#[path = "common/print.rs"]
|
||||
mod print;
|
||||
|
||||
use dyna3::engine::{
|
||||
realize_gram,
|
||||
sphere,
|
||||
ConfigNeighborhood,
|
||||
ConstraintProblem
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let mut problem = ConstraintProblem::from_guess({
|
||||
|
@ -14,20 +22,13 @@ fn main() {
|
|||
problem.gram.push_sym(j, k, if j == k { 1.0 } else { -1.0 });
|
||||
}
|
||||
}
|
||||
println!();
|
||||
let (config, _, success, history) = realize_gram(
|
||||
let realization = realize_gram(
|
||||
&problem, 1.0e-12, 0.5, 0.9, 1.1, 200, 110
|
||||
);
|
||||
print!("\nCompleted Gram matrix:{}", config.tr_mul(&*Q) * &config);
|
||||
if success {
|
||||
println!("Target accuracy achieved!");
|
||||
} else {
|
||||
println!("Failed to reach target accuracy");
|
||||
}
|
||||
println!("Steps: {}", history.scaled_loss.len() - 1);
|
||||
println!("Loss: {}", history.scaled_loss.last().unwrap());
|
||||
println!("\nStep │ Loss\n─────┼────────────────────────────────");
|
||||
for (step, scaled_loss) in history.scaled_loss.into_iter().enumerate() {
|
||||
println!("{:<4} │ {}", step, scaled_loss);
|
||||
print::title("Three spheres");
|
||||
print::realization_diagnostics(&realization);
|
||||
if let Ok(ConfigNeighborhood{ config, .. }) = realization.result {
|
||||
print::gram_matrix(&config);
|
||||
}
|
||||
print::loss_history(&realization.history);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue