Tue, 22 Oct 2024 08:27:45 -0500
Save log to a CSV file
Cargo.toml | file | annotate | diff | comparison | revisions | |
src/cube.rs | file | annotate | diff | comparison | revisions | |
src/fb.rs | file | annotate | diff | comparison | revisions | |
src/main.rs | file | annotate | diff | comparison | revisions |
--- a/Cargo.toml Mon Oct 21 23:07:01 2024 -0500 +++ b/Cargo.toml Tue Oct 22 08:27:45 2024 -0500 @@ -22,3 +22,4 @@ alg_tools = { version = "~0.3.0-dev", path = "../alg_tools", default-features = false } colored = "~2.0.0" image = "~0.24.3" +serde_repr = "0.1"
--- a/src/cube.rs Mon Oct 21 23:07:01 2024 -0500 +++ b/src/cube.rs Tue Oct 22 08:27:45 2024 -0500 @@ -1,19 +1,20 @@ -use core::f64; - +use serde_repr::*; +use serde::Serialize; use alg_tools::loc::Loc; use alg_tools::norms::{Norm, L2}; use crate::manifold::{ManifoldPoint, EmbeddedManifoldPoint}; -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Face {F1, F2, F3, F4, F5, F6} +#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum Face {F1 = 1, F2 = 2, F3 = 3, F4 = 4, F5 = 5, F6 = 6} use Face::*; pub type Point = Loc<f64, 2>; pub type AdjacentFaces = [Face; 4]; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize)] pub enum Path { Direct { destination : Face }, Indirect { destination : Face, intermediate : Face }, @@ -216,7 +217,7 @@ } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize)] pub struct OnCube { face : Face, point : Point, @@ -244,6 +245,10 @@ } (best_tan, best_len) } + + pub fn face(&self) -> Face { + self.face + } }
--- a/src/fb.rs Mon Oct 21 23:07:01 2024 -0500 +++ b/src/fb.rs Tue Oct 22 08:27:45 2024 -0500 @@ -4,7 +4,6 @@ use serde::Serialize; use std::iter::Sum as SumTrait; use colored::ColoredString; - use crate::manifold::{EmbeddedManifoldPoint, ManifoldPoint}; /// Trait for function objects that implement gradients @@ -40,10 +39,13 @@ fn prox(&self, τ : f64, x : M) -> M; } +/// This structure is used to store information from algorithm iterations #[derive(Clone,Debug,Serialize)] pub struct IterInfo<M> { - value : f64, - point : M, + /// Function value + pub value : f64, + /// Current iterate + pub point : M, } impl<M : ManifoldPoint + EmbeddedManifoldPoint> LogRepr for IterInfo<M> { @@ -55,6 +57,11 @@ } } +/// The forward-backward method on manifolds. +/// +/// `f` is the smooth, `g` the nonsmooth function, `x` the initial iterate, +/// `τ` the step length parameter, and `iterator` controls the iteration count +/// and verbosity. Return the final iterate. pub fn forward_backward<M, F, G, I>( f : &F, g : &G, @@ -66,10 +73,13 @@ F : Desc<M> + Mapping<M, Codomain = f64>, G : Prox<M> + Mapping<M, Codomain = f64>, I : AlgIteratorFactory<IterInfo<M>> { - + + // Perform as many iterations as requested by `iterator`. for i in iterator.iter() { + // Forward-backward step x = g.prox(τ, f.desc(τ, x)); + // If requested by `iterator`, calculate function value and store iterate. i.if_verbose(|| { IterInfo { value : f.apply(&x) + g.apply(&x), @@ -78,5 +88,6 @@ }) } + // Return final iterate. x }
--- a/src/main.rs Mon Oct 21 23:07:01 2024 -0500 +++ b/src/main.rs Tue Oct 22 08:27:45 2024 -0500 @@ -5,9 +5,13 @@ #![allow(mixed_script_confusables)] #![allow(confusable_idents)] +use serde::Serialize; use dist::DistToSquaredDiv2; -use fb::forward_backward; +use fb::{forward_backward, IterInfo}; use manifold::EmbeddedManifoldPoint; +use alg_tools::logger::Logger; +use alg_tools::tabledump::TableDump; +use alg_tools::error::DynError; use cube::*; use image::{ ImageFormat, @@ -22,15 +26,29 @@ mod zero; fn main() { - simple_test() + simple_cube_test().unwrap() } -fn simple_test() { +/// Helper structure for saving the log into a CSV file +#[derive(Serialize)] +struct CSVLog { + iter : usize, + value : f64, + face : Face, + x : f64, + y : f64, + z : f64 +} + +static PREFIX : &str = "res"; + +/// A simple test on the cube +fn simple_cube_test() -> DynError { use alg_tools::loc::Loc; use Face::*; use zero::ZeroFn; use alg_tools::mapping::{Sum, Apply}; - use alg_tools::iterate::{AlgIteratorOptions, Verbose}; + use alg_tools::iterate::{AlgIteratorOptions, AlgIteratorFactory, Verbose}; let points = [ //OnCube::new(F1, Loc([0.5, 0.5])), @@ -47,21 +65,37 @@ let f = Sum::new(points.into_iter().map(DistToSquaredDiv2)); let g = ZeroFn::new(); let τ = 0.1; + + let mut logger = Logger::new(); + let logmap = |iter, IterInfo { value, point } : IterInfo<OnCube>| { + let Loc([x,y,z]) = point.embedded_coords(); + let face = point.face(); + CSVLog { iter, value, face, x, y, z } + }; let iter = AlgIteratorOptions{ max_iter : 100, verbose_iter : Verbose::Every(1), .. Default::default() - }; + }.mapped(logmap) + .into_log(&mut logger); let x̂ = forward_backward(&f, &g, x, τ, iter); println!("result = {}\n{:?}", x̂.embedded_coords(), &x̂); + std::fs::create_dir_all(PREFIX)?; + + logger.write_csv(format!("{PREFIX}/log.txt"))?; + for face in Face::all() { - write_face(format!("{face}"), face, 128, |x| f.apply(x) + g.apply(x)) + write_face(format!("{PREFIX}/{face}"), face, 128, |x| f.apply(x) + g.apply(x))?; } + + Ok(()) } -fn write_face(filename : String, face : Face, n : usize, mut f : impl FnMut(&OnCube) -> f64) { +/// Writes the values of `f` on `face` of a [`OnCube`] into a PNG file +/// with resolution `n × n`. +fn write_face(filename : String, face : Face, n : usize, mut f : impl FnMut(&OnCube) -> f64) -> DynError { use alg_tools::lingrid::LinSpace; use alg_tools::loc::Loc; use alg_tools::types::*; @@ -84,6 +118,7 @@ *p = Rgb(rgb.map(|v| (v*(u8::RANGE_MAX as f64)) as u8)) }); - img.save_with_format(format!("{filename}.png"), ImageFormat::Png) - .expect("Image save error"); + img.save_with_format(format!("{filename}.png"), ImageFormat::Png)?; + + Ok(()) }