extern crate eigenvalues;
extern crate nalgebra as na;
use streaming_iterator::*;
use iterative_methods::conjugate_gradient::ConjugateGradient;
use iterative_methods::utils::make_3x3_pd_system_2;
use iterative_methods::*;
use ndarray::{rcarr1, ArcArray1};
pub type V = ArcArray1<f64>;
fn cg_demo_pt1() {
let p = make_3x3_pd_system_2();
let mut cg_iter = ConjugateGradient::for_problem(&p);
while let Some(result) = cg_iter.next() {
let res = result.a.dot(&result.solution) - &result.b;
let res_squared_length = res.dot(&res);
println!(
"||Ax - b||_2 = {:.5}, for x = {:+.3}, residual = {:+.3}",
res_squared_length.sqrt(),
result.solution,
res
);
if res_squared_length < 1e-3 {
break;
}
}
}
fn residual_l2(result: &ConjugateGradient) -> f64 {
let res = result.a.dot(&result.solution) - &result.b;
res.dot(&res).sqrt()
}
fn cg_demo_pt2_1() {
let p = make_3x3_pd_system_2();
let cg_iter = ConjugateGradient::for_problem(&p);
let cg_iter = assess(cg_iter, residual_l2);
let mut cg_iter = take_until(cg_iter, |ar| ar.annotation < 1e-3);
while let Some(AnnotatedResult {
result: cgi,
annotation: euc,
}) = cg_iter.next()
{
println!("||Ax - b||_2 = {:.5}, for x = {:.4}", euc, cgi.solution);
}
}
fn a_distance(result: &ConjugateGradient, optimum: V) -> f64 {
let error = &result.solution - &optimum;
error.dot(&result.a.dot(&error)).sqrt()
}
fn residual_linf(result: &ConjugateGradient) -> f64 {
(result.a.dot(&result.solution) - &result.b).fold(0.0, |m, e| m.max(e.abs()))
}
fn cg_demo_pt2_2() {
let p = make_3x3_pd_system_2();
let optimum = rcarr1(&[-4.0, 6., -4.]);
let cg_iter = ConjugateGradient::for_problem(&p);
let cg_iter = cg_iter.take(80);
let cg_iter = time(cg_iter);
let cg_iter = assess(cg_iter, |TimedResult { result, .. }| {
(
residual_l2(result),
residual_linf(result),
a_distance(result, optimum.clone()),
)
});
fn small_residual((euc, linf, _): &(f64, f64, f64)) -> bool {
euc < &1e-3 && linf < &1e-3
}
let mut cg_iter = take_until(cg_iter, |ar| small_residual(&ar.annotation));
while let Some(AnnotatedResult {
annotation: (euc, linf, a_dist),
result:
TimedResult {
result,
start_time,
duration,
},
}) = cg_iter.next()
{
println!(
"{:8} : {:6}, \
||Ax - b||_2 = {:.3}, ||Ax - b||_inf = {:.3}, ||x-x*||_A = {:.3}, \
for x = {:+.3}",
start_time.as_nanos(),
duration.as_nanos(),
euc,
linf,
a_dist,
result.solution,
);
}
}
fn main() {
println!("Part 1 demo: method in iterator, logic in loop.");
cg_demo_pt1();
println!("Part 2 demo 1: method in iterator, assessment in adaptor, rest in loop.");
cg_demo_pt2_1();
println!("Part 2 demo 2: logic via adaptors, I/O in loop.");
cg_demo_pt2_2();
}