54 use alg_tools::direct_product::Pair; |
54 use alg_tools::direct_product::Pair; |
55 |
55 |
56 use crate::kernels::*; |
56 use crate::kernels::*; |
57 use crate::types::*; |
57 use crate::types::*; |
58 use crate::measures::*; |
58 use crate::measures::*; |
59 use crate::measures::merging::SpikeMerging; |
59 use crate::measures::merging::{SpikeMerging,SpikeMergingMethod}; |
60 use crate::forward_model::*; |
60 use crate::forward_model::*; |
61 use crate::forward_model::sensor_grid::{ |
61 use crate::forward_model::sensor_grid::{ |
62 SensorGrid, |
62 SensorGrid, |
63 SensorGridBT, |
63 SensorGridBT, |
64 //SensorGridBTFN, |
64 //SensorGridBTFN, |
144 } |
144 } |
145 |
145 |
146 impl<F : ClapFloat> AlgorithmConfig<F> { |
146 impl<F : ClapFloat> AlgorithmConfig<F> { |
147 /// Override supported parameters based on the command line. |
147 /// Override supported parameters based on the command line. |
148 pub fn cli_override(self, cli : &AlgorithmOverrides<F>) -> Self { |
148 pub fn cli_override(self, cli : &AlgorithmOverrides<F>) -> Self { |
|
149 let override_merging = |g : SpikeMergingMethod<F>| { |
|
150 SpikeMergingMethod { |
|
151 enabled : cli.merge.unwrap_or(g.enabled), |
|
152 radius : cli.merge_radius.unwrap_or(g.radius), |
|
153 interp : cli.merge_interp.unwrap_or(g.interp), |
|
154 } |
|
155 }; |
149 let override_fb_generic = |g : FBGenericConfig<F>| { |
156 let override_fb_generic = |g : FBGenericConfig<F>| { |
150 FBGenericConfig { |
157 FBGenericConfig { |
151 bootstrap_insertions : cli.bootstrap_insertions |
158 bootstrap_insertions : cli.bootstrap_insertions |
152 .as_ref() |
159 .as_ref() |
153 .map_or(g.bootstrap_insertions, |
160 .map_or(g.bootstrap_insertions, |
154 |n| Some((n[0], n[1]))), |
161 |n| Some((n[0], n[1]))), |
155 merge_every : cli.merge_every.unwrap_or(g.merge_every), |
162 merge_every : cli.merge_every.unwrap_or(g.merge_every), |
156 merging : cli.merging.clone().unwrap_or(g.merging), |
163 merging : override_merging(g.merging), |
157 final_merging : cli.final_merging.clone().unwrap_or(g.final_merging), |
164 final_merging : cli.final_merging.unwrap_or(g.final_merging), |
|
165 fitness_merging : cli.fitness_merging.unwrap_or(g.fitness_merging), |
158 tolerance: cli.tolerance.as_ref().map(unpack_tolerance).unwrap_or(g.tolerance), |
166 tolerance: cli.tolerance.as_ref().map(unpack_tolerance).unwrap_or(g.tolerance), |
159 .. g |
167 .. g |
160 } |
168 } |
161 }; |
169 }; |
162 let override_transport = |g : TransportConfig<F>| { |
170 let override_transport = |g : TransportConfig<F>| { |
163 TransportConfig { |
171 TransportConfig { |
164 θ0 : cli.theta0.unwrap_or(g.θ0), |
172 θ0 : cli.theta0.unwrap_or(g.θ0), |
165 tolerance_ω: cli.transport_tolerance_omega.unwrap_or(g.tolerance_ω), |
173 tolerance_mult_pos: cli.transport_tolerance_pos.unwrap_or(g.tolerance_mult_pos), |
166 tolerance_dv: cli.transport_tolerance_dv.unwrap_or(g.tolerance_dv), |
174 tolerance_mult_pri: cli.transport_tolerance_pri.unwrap_or(g.tolerance_mult_pri), |
167 adaptation: cli.transport_adaptation.unwrap_or(g.adaptation), |
175 adaptation: cli.transport_adaptation.unwrap_or(g.adaptation), |
168 .. g |
176 .. g |
169 } |
177 } |
170 }; |
178 }; |
171 |
179 |
187 acceleration : cli.acceleration.unwrap_or(pdps.acceleration), |
195 acceleration : cli.acceleration.unwrap_or(pdps.acceleration), |
188 generic : override_fb_generic(pdps.generic), |
196 generic : override_fb_generic(pdps.generic), |
189 .. pdps |
197 .. pdps |
190 }, prox), |
198 }, prox), |
191 FW(fw) => FW(FWConfig { |
199 FW(fw) => FW(FWConfig { |
192 merging : cli.merging.clone().unwrap_or(fw.merging), |
200 merging : override_merging(fw.merging), |
193 tolerance : cli.tolerance.as_ref().map(unpack_tolerance).unwrap_or(fw.tolerance), |
201 tolerance : cli.tolerance.as_ref().map(unpack_tolerance).unwrap_or(fw.tolerance), |
194 .. fw |
202 .. fw |
195 }), |
203 }), |
196 SlidingFB(sfb, prox) => SlidingFB(SlidingFBConfig { |
204 SlidingFB(sfb, prox) => SlidingFB(SlidingFBConfig { |
197 τ0 : cli.tau0.unwrap_or(sfb.τ0), |
205 τ0 : cli.tau0.unwrap_or(sfb.τ0), |
280 |
288 |
281 impl DefaultAlgorithm { |
289 impl DefaultAlgorithm { |
282 /// Returns the algorithm configuration corresponding to the algorithm shorthand |
290 /// Returns the algorithm configuration corresponding to the algorithm shorthand |
283 pub fn default_config<F : Float>(&self) -> AlgorithmConfig<F> { |
291 pub fn default_config<F : Float>(&self) -> AlgorithmConfig<F> { |
284 use DefaultAlgorithm::*; |
292 use DefaultAlgorithm::*; |
|
293 let radon_insertion = FBGenericConfig { |
|
294 merging : SpikeMergingMethod{ interp : false, .. Default::default() }, |
|
295 inner : InnerSettings { |
|
296 method : InnerMethod::PDPS, // SSN not implemented |
|
297 .. Default::default() |
|
298 }, |
|
299 .. Default::default() |
|
300 }; |
285 match *self { |
301 match *self { |
286 FB => AlgorithmConfig::FB(Default::default(), ProxTerm::Wave), |
302 FB => AlgorithmConfig::FB(Default::default(), ProxTerm::Wave), |
287 FISTA => AlgorithmConfig::FISTA(Default::default(), ProxTerm::Wave), |
303 FISTA => AlgorithmConfig::FISTA(Default::default(), ProxTerm::Wave), |
288 FW => AlgorithmConfig::FW(Default::default()), |
304 FW => AlgorithmConfig::FW(Default::default()), |
289 FWRelax => AlgorithmConfig::FW(FWConfig{ |
305 FWRelax => AlgorithmConfig::FW(FWConfig{ |
295 SlidingPDPS => AlgorithmConfig::SlidingPDPS(Default::default(), ProxTerm::Wave), |
311 SlidingPDPS => AlgorithmConfig::SlidingPDPS(Default::default(), ProxTerm::Wave), |
296 ForwardPDPS => AlgorithmConfig::ForwardPDPS(Default::default(), ProxTerm::Wave), |
312 ForwardPDPS => AlgorithmConfig::ForwardPDPS(Default::default(), ProxTerm::Wave), |
297 |
313 |
298 // Radon variants |
314 // Radon variants |
299 |
315 |
300 RadonFB => AlgorithmConfig::FB(Default::default(), ProxTerm::RadonSquared), |
316 RadonFB => AlgorithmConfig::FB( |
301 RadonFISTA => AlgorithmConfig::FISTA(Default::default(), ProxTerm::RadonSquared), |
317 FBConfig{ generic : radon_insertion, ..Default::default() }, |
302 RadonPDPS => AlgorithmConfig::PDPS(Default::default(), ProxTerm::RadonSquared), |
318 ProxTerm::RadonSquared |
303 RadonSlidingFB => AlgorithmConfig::SlidingFB(Default::default(), ProxTerm::RadonSquared), |
319 ), |
304 RadonSlidingPDPS => AlgorithmConfig::SlidingPDPS(Default::default(), ProxTerm::RadonSquared), |
320 RadonFISTA => AlgorithmConfig::FISTA( |
305 RadonForwardPDPS => AlgorithmConfig::ForwardPDPS(Default::default(), ProxTerm::RadonSquared), |
321 FBConfig{ generic : radon_insertion, ..Default::default() }, |
|
322 ProxTerm::RadonSquared |
|
323 ), |
|
324 RadonPDPS => AlgorithmConfig::PDPS( |
|
325 PDPSConfig{ generic : radon_insertion, ..Default::default() }, |
|
326 ProxTerm::RadonSquared |
|
327 ), |
|
328 RadonSlidingFB => AlgorithmConfig::SlidingFB( |
|
329 SlidingFBConfig{ insertion : radon_insertion, ..Default::default() }, |
|
330 ProxTerm::RadonSquared |
|
331 ), |
|
332 RadonSlidingPDPS => AlgorithmConfig::SlidingPDPS( |
|
333 SlidingPDPSConfig{ insertion : radon_insertion, ..Default::default() }, |
|
334 ProxTerm::RadonSquared |
|
335 ), |
|
336 RadonForwardPDPS => AlgorithmConfig::ForwardPDPS( |
|
337 ForwardPDPSConfig{ insertion : radon_insertion, ..Default::default() }, |
|
338 ProxTerm::RadonSquared |
|
339 ), |
306 } |
340 } |
307 } |
341 } |
308 |
342 |
309 /// Returns the [`Named`] algorithm corresponding to the algorithm shorthand |
343 /// Returns the [`Named`] algorithm corresponding to the algorithm shorthand |
310 pub fn get_named<F : Float>(&self) -> Named<AlgorithmConfig<F>> { |
344 pub fn get_named<F : Float>(&self) -> Named<AlgorithmConfig<F>> { |
416 |
456 |
417 |
457 |
418 /// Struct for experiment configurations |
458 /// Struct for experiment configurations |
419 #[derive(Debug, Clone, Serialize)] |
459 #[derive(Debug, Clone, Serialize)] |
420 pub struct ExperimentV2<F, NoiseDistr, S, K, P, const N : usize> |
460 pub struct ExperimentV2<F, NoiseDistr, S, K, P, const N : usize> |
421 where F : Float, |
461 where F : Float + ClapFloat, |
422 [usize; N] : Serialize, |
462 [usize; N] : Serialize, |
423 NoiseDistr : Distribution<F>, |
463 NoiseDistr : Distribution<F>, |
424 S : Sensor<F, N>, |
464 S : Sensor<F, N>, |
425 P : Spread<F, N>, |
465 P : Spread<F, N>, |
426 K : SimpleConvolutionKernel<F, N>, |
466 K : SimpleConvolutionKernel<F, N>, |
446 /// For plotting : how wide should the kernels be plotted |
486 /// For plotting : how wide should the kernels be plotted |
447 pub kernel_plot_width : F, |
487 pub kernel_plot_width : F, |
448 /// Data term |
488 /// Data term |
449 pub dataterm : DataTerm, |
489 pub dataterm : DataTerm, |
450 /// A map of default configurations for algorithms |
490 /// A map of default configurations for algorithms |
451 #[serde(skip)] |
491 pub algorithm_overrides : HashMap<DefaultAlgorithm, AlgorithmOverrides<F>>, |
452 pub algorithm_defaults : HashMap<DefaultAlgorithm, AlgorithmConfig<F>>, |
492 /// Default merge radius |
|
493 pub default_merge_radius : F, |
453 } |
494 } |
454 |
495 |
455 #[derive(Debug, Clone, Serialize)] |
496 #[derive(Debug, Clone, Serialize)] |
456 pub struct ExperimentBiased<F, NoiseDistr, S, K, P, B, const N : usize> |
497 pub struct ExperimentBiased<F, NoiseDistr, S, K, P, B, const N : usize> |
457 where F : Float, |
498 where F : Float + ClapFloat, |
458 [usize; N] : Serialize, |
499 [usize; N] : Serialize, |
459 NoiseDistr : Distribution<F>, |
500 NoiseDistr : Distribution<F>, |
460 S : Sensor<F, N>, |
501 S : Sensor<F, N>, |
461 P : Spread<F, N>, |
502 P : Spread<F, N>, |
462 K : SimpleConvolutionKernel<F, N>, |
503 K : SimpleConvolutionKernel<F, N>, |
475 /// Run all algorithms provided, or default algorithms if none provided, on the experiment. |
516 /// Run all algorithms provided, or default algorithms if none provided, on the experiment. |
476 fn runall(&self, cli : &CommandLineArgs, |
517 fn runall(&self, cli : &CommandLineArgs, |
477 algs : Option<Vec<Named<AlgorithmConfig<F>>>>) -> DynError; |
518 algs : Option<Vec<Named<AlgorithmConfig<F>>>>) -> DynError; |
478 |
519 |
479 /// Return algorithm default config |
520 /// Return algorithm default config |
480 fn algorithm_defaults(&self, alg : DefaultAlgorithm) -> Option<AlgorithmConfig<F>>; |
521 fn algorithm_overrides(&self, alg : DefaultAlgorithm) -> AlgorithmOverrides<F>; |
481 } |
522 } |
482 |
523 |
483 /// Helper function to print experiment start message and save setup. |
524 /// Helper function to print experiment start message and save setup. |
484 /// Returns saving prefix. |
525 /// Returns saving prefix. |
485 fn start_experiment<E, S>( |
526 fn start_experiment<E, S>( |
492 S : Serialize, |
533 S : Serialize, |
493 { |
534 { |
494 let Named { name : experiment_name, data } = experiment; |
535 let Named { name : experiment_name, data } = experiment; |
495 |
536 |
496 println!("{}\n{}", |
537 println!("{}\n{}", |
497 format!("Performing experiment {}…", experiment_name).cyan(), |
538 format!("Performing experiment {}…", experiment_name).cyan(), |
498 format!("{:?}", data).bright_black()); |
539 format!("Experiment settings: {}", serde_json::to_string(&data)?).bright_black()); |
499 |
540 |
500 // Set up output directory |
541 // Set up output directory |
501 let prefix = format!("{}/{}/", cli.outdir, experiment_name); |
542 let prefix = format!("{}/{}/", cli.outdir, experiment_name); |
502 |
543 |
503 // Save experiment configuration and statistics |
544 // Save experiment configuration and statistics |
523 Timed<IterInfo<F, N>>, |
564 Timed<IterInfo<F, N>>, |
524 TimingIteratorFactory<BasicAlgIteratorFactory<IterInfo<F, N>>> |
565 TimingIteratorFactory<BasicAlgIteratorFactory<IterInfo<F, N>>> |
525 >; |
566 >; |
526 |
567 |
527 /// Helper function to run all algorithms on an experiment. |
568 /// Helper function to run all algorithms on an experiment. |
528 fn do_runall<F : Float, Z, const N : usize>( |
569 fn do_runall<F : Float + for<'b> Deserialize<'b>, Z, const N : usize>( |
529 experiment_name : &String, |
570 experiment_name : &String, |
530 prefix : &String, |
571 prefix : &String, |
531 cli : &CommandLineArgs, |
572 cli : &CommandLineArgs, |
532 algorithms : Vec<Named<AlgorithmConfig<F>>>, |
573 algorithms : Vec<Named<AlgorithmConfig<F>>>, |
533 plotgrid : LinSpace<Loc<F, N>, [usize; N]>, |
574 plotgrid : LinSpace<Loc<F, N>, [usize; N]>, |
545 let mut logs = Vec::new(); |
586 let mut logs = Vec::new(); |
546 |
587 |
547 let iterator_options = AlgIteratorOptions{ |
588 let iterator_options = AlgIteratorOptions{ |
548 max_iter : cli.max_iter, |
589 max_iter : cli.max_iter, |
549 verbose_iter : cli.verbose_iter |
590 verbose_iter : cli.verbose_iter |
550 .map_or(Verbose::Logarithmic(10), |
591 .map_or(Verbose::LogarithmicCap{base : 10, cap : 2}, |
551 |n| Verbose::Every(n)), |
592 |n| Verbose::Every(n)), |
552 quiet : cli.quiet, |
593 quiet : cli.quiet, |
553 }; |
594 }; |
554 |
595 |
555 // Run the algorithm(s) |
596 // Run the algorithm(s) |
563 .into_log(&mut logger); |
604 .into_log(&mut logger); |
564 |
605 |
565 let running = if !cli.quiet { |
606 let running = if !cli.quiet { |
566 format!("{}\n{}\n{}\n", |
607 format!("{}\n{}\n{}\n", |
567 format!("Running {} on experiment {}…", alg_name, experiment_name).cyan(), |
608 format!("Running {} on experiment {}…", alg_name, experiment_name).cyan(), |
568 format!("{:?}", iterator_options).bright_black(), |
609 format!("Iteration settings: {}", serde_json::to_string(&iterator_options)?).bright_black(), |
569 format!("{:?}", alg).bright_black()) |
610 format!("Algorithm settings: {}", serde_json::to_string(&alg)?).bright_black()) |
570 } else { |
611 } else { |
571 "".to_string() |
612 "".to_string() |
572 }; |
613 }; |
573 // |
614 // |
574 // The following is for postprocessing, which has been disabled anyway. |
615 // The following is for postprocessing, which has been disabled anyway. |
612 write_json(mkname("stats.json"), &AlgorithmStats { cpu_time, elapsed })?; |
653 write_json(mkname("stats.json"), &AlgorithmStats { cpu_time, elapsed })?; |
613 μ.write_csv(mkname("reco.txt"))?; |
654 μ.write_csv(mkname("reco.txt"))?; |
614 save_extra(mkname(""), z)?; |
655 save_extra(mkname(""), z)?; |
615 //logger.write_csv(mkname("log.txt"))?; |
656 //logger.write_csv(mkname("log.txt"))?; |
616 logs.push((mkname("log.txt"), logger)); |
657 logs.push((mkname("log.txt"), logger)); |
617 } |
658 } |
618 |
659 |
619 save_logs(logs) |
660 save_logs(logs, format!("{prefix}valuerange.json"), cli.load_valuerange) |
620 } |
661 } |
621 |
662 |
622 #[replace_float_literals(F::cast_from(literal))] |
663 #[replace_float_literals(F::cast_from(literal))] |
623 impl<F, NoiseDistr, S, K, P, /*PreadjointCodomain, */ const N : usize> RunnableExperiment<F> for |
664 impl<F, NoiseDistr, S, K, P, /*PreadjointCodomain, */ const N : usize> RunnableExperiment<F> for |
624 Named<ExperimentV2<F, NoiseDistr, S, K, P, N>> |
665 Named<ExperimentV2<F, NoiseDistr, S, K, P, N>> |
625 where |
666 where |
626 F : ClapFloat + nalgebra::RealField + ToNalgebraRealField<MixedType=F>, |
667 F : ClapFloat + nalgebra::RealField + ToNalgebraRealField<MixedType=F> |
|
668 + Default + for<'b> Deserialize<'b>, |
627 [usize; N] : Serialize, |
669 [usize; N] : Serialize, |
628 S : Sensor<F, N> + Copy + Serialize + std::fmt::Debug, |
670 S : Sensor<F, N> + Copy + Serialize + std::fmt::Debug, |
629 P : Spread<F, N> + Copy + Serialize + std::fmt::Debug, |
671 P : Spread<F, N> + Copy + Serialize + std::fmt::Debug, |
630 Convolution<S, P>: Spread<F, N> + Bounded<F> + LocalAnalysis<F, Bounds<F>, N> + Copy |
672 Convolution<S, P>: Spread<F, N> + Bounded<F> + LocalAnalysis<F, Bounds<F>, N> + Copy |
631 // TODO: shold not have differentiability as a requirement, but |
673 // TODO: shold not have differentiability as a requirement, but |
653 // DefaultSeminormOp<F, K, N> : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
695 // DefaultSeminormOp<F, K, N> : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
654 // RadonSquared : ProxPenalty<F, PreadjointCodomain, RadonRegTerm<F>, N>, |
696 // RadonSquared : ProxPenalty<F, PreadjointCodomain, RadonRegTerm<F>, N>, |
655 // RadonSquared : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
697 // RadonSquared : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
656 { |
698 { |
657 |
699 |
658 fn algorithm_defaults(&self, alg : DefaultAlgorithm) -> Option<AlgorithmConfig<F>> { |
700 fn algorithm_overrides(&self, alg : DefaultAlgorithm) -> AlgorithmOverrides<F> { |
659 self.data.algorithm_defaults.get(&alg).cloned() |
701 AlgorithmOverrides { |
|
702 merge_radius : Some(self.data.default_merge_radius), |
|
703 .. self.data.algorithm_overrides.get(&alg).cloned().unwrap_or(Default::default()) |
|
704 } |
660 } |
705 } |
661 |
706 |
662 fn runall(&self, cli : &CommandLineArgs, |
707 fn runall(&self, cli : &CommandLineArgs, |
663 algs : Option<Vec<Named<AlgorithmConfig<F>>>>) -> DynError { |
708 algs : Option<Vec<Named<AlgorithmConfig<F>>>>) -> DynError { |
664 // Get experiment configuration |
709 // Get experiment configuration |
885 |
930 |
886 #[replace_float_literals(F::cast_from(literal))] |
931 #[replace_float_literals(F::cast_from(literal))] |
887 impl<F, NoiseDistr, S, K, P, B, /*PreadjointCodomain,*/ const N : usize> RunnableExperiment<F> for |
932 impl<F, NoiseDistr, S, K, P, B, /*PreadjointCodomain,*/ const N : usize> RunnableExperiment<F> for |
888 Named<ExperimentBiased<F, NoiseDistr, S, K, P, B, N>> |
933 Named<ExperimentBiased<F, NoiseDistr, S, K, P, B, N>> |
889 where |
934 where |
890 F : ClapFloat + nalgebra::RealField + ToNalgebraRealField<MixedType=F>, |
935 F : ClapFloat + nalgebra::RealField + ToNalgebraRealField<MixedType=F> |
|
936 + Default + for<'b> Deserialize<'b>, |
891 [usize; N] : Serialize, |
937 [usize; N] : Serialize, |
892 S : Sensor<F, N> + Copy + Serialize + std::fmt::Debug, |
938 S : Sensor<F, N> + Copy + Serialize + std::fmt::Debug, |
893 P : Spread<F, N> + Copy + Serialize + std::fmt::Debug, |
939 P : Spread<F, N> + Copy + Serialize + std::fmt::Debug, |
894 Convolution<S, P>: Spread<F, N> + Bounded<F> + LocalAnalysis<F, Bounds<F>, N> + Copy |
940 Convolution<S, P>: Spread<F, N> + Bounded<F> + LocalAnalysis<F, Bounds<F>, N> + Copy |
895 // TODO: shold not have differentiability as a requirement, but |
941 // TODO: shold not have differentiability as a requirement, but |
918 // DefaultSeminormOp<F, K, N> : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
964 // DefaultSeminormOp<F, K, N> : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
919 // RadonSquared : ProxPenalty<F, PreadjointCodomain, RadonRegTerm<F>, N>, |
965 // RadonSquared : ProxPenalty<F, PreadjointCodomain, RadonRegTerm<F>, N>, |
920 // RadonSquared : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
966 // RadonSquared : ProxPenalty<F, PreadjointCodomain, NonnegRadonRegTerm<F>, N>, |
921 { |
967 { |
922 |
968 |
923 fn algorithm_defaults(&self, alg : DefaultAlgorithm) -> Option<AlgorithmConfig<F>> { |
969 fn algorithm_overrides(&self, alg : DefaultAlgorithm) -> AlgorithmOverrides<F> { |
924 self.data.base.algorithm_defaults.get(&alg).cloned() |
970 AlgorithmOverrides { |
|
971 merge_radius : Some(self.data.base.default_merge_radius), |
|
972 .. self.data.base.algorithm_overrides.get(&alg).cloned().unwrap_or(Default::default()) |
|
973 } |
925 } |
974 } |
926 |
975 |
927 fn runall(&self, cli : &CommandLineArgs, |
976 fn runall(&self, cli : &CommandLineArgs, |
928 algs : Option<Vec<Named<AlgorithmConfig<F>>>>) -> DynError { |
977 algs : Option<Vec<Named<AlgorithmConfig<F>>>>) -> DynError { |
929 // Get experiment configuration |
978 // Get experiment configuration |
1075 Ok((μ, z)) |
1124 Ok((μ, z)) |
1076 }) |
1125 }) |
1077 } |
1126 } |
1078 } |
1127 } |
1079 |
1128 |
|
1129 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
|
1130 struct ValueRange<F : Float> { |
|
1131 ini : F, |
|
1132 min : F, |
|
1133 } |
|
1134 |
|
1135 impl<F : Float> ValueRange<F> { |
|
1136 fn expand_with(self, other : Self) -> Self { |
|
1137 ValueRange { |
|
1138 ini : self.ini.max(other.ini), |
|
1139 min : self.min.min(other.min), |
|
1140 } |
|
1141 } |
|
1142 } |
1080 |
1143 |
1081 /// Calculative minimum and maximum values of all the `logs`, and save them into |
1144 /// Calculative minimum and maximum values of all the `logs`, and save them into |
1082 /// corresponding file names given as the first elements of the tuples in the vectors. |
1145 /// corresponding file names given as the first elements of the tuples in the vectors. |
1083 fn save_logs<F : Float, const N : usize>( |
1146 fn save_logs<F : Float + for<'b> Deserialize<'b>, const N : usize>( |
1084 logs : Vec<(String, Logger<Timed<IterInfo<F, N>>>)> |
1147 logs : Vec<(String, Logger<Timed<IterInfo<F, N>>>)>, |
|
1148 valuerange_file : String, |
|
1149 load_valuerange : bool, |
1085 ) -> DynError { |
1150 ) -> DynError { |
1086 // Process logs for relative values |
1151 // Process logs for relative values |
1087 println!("{}", "Processing logs…"); |
1152 println!("{}", "Processing logs…"); |
1088 |
|
1089 |
1153 |
1090 // Find minimum value and initial value within a single log |
1154 // Find minimum value and initial value within a single log |
1091 let proc_single_log = |log : &Logger<Timed<IterInfo<F, N>>>| { |
1155 let proc_single_log = |log : &Logger<Timed<IterInfo<F, N>>>| { |
1092 let d = log.data(); |
1156 let d = log.data(); |
1093 let mi = d.iter() |
1157 let mi = d.iter() |
1094 .map(|i| i.data.value) |
1158 .map(|i| i.data.value) |
1095 .reduce(NumTraitsFloat::min); |
1159 .reduce(NumTraitsFloat::min); |
1096 d.first() |
1160 d.first() |
1097 .map(|i| i.data.value) |
1161 .map(|i| i.data.value) |
1098 .zip(mi) |
1162 .zip(mi) |
|
1163 .map(|(ini, min)| ValueRange{ ini, min }) |
1099 }; |
1164 }; |
1100 |
1165 |
1101 // Find minimum and maximum value over all logs |
1166 // Find minimum and maximum value over all logs |
1102 let (v_ini, v_min) = logs.iter() |
1167 let mut v = logs.iter() |
1103 .filter_map(|&(_, ref log)| proc_single_log(log)) |
1168 .filter_map(|&(_, ref log)| proc_single_log(log)) |
1104 .reduce(|(i1, m1), (i2, m2)| (i1.max(i2), m1.min(m2))) |
1169 .reduce(|v1, v2| v1.expand_with(v2)) |
1105 .ok_or(anyhow!("No algorithms found"))?; |
1170 .ok_or(anyhow!("No algorithms found"))?; |
|
1171 |
|
1172 // Load existing range |
|
1173 if load_valuerange && std::fs::metadata(&valuerange_file).is_ok() { |
|
1174 let data = std::fs::read_to_string(&valuerange_file)?; |
|
1175 v = v.expand_with(serde_json::from_str(&data)?); |
|
1176 } |
1106 |
1177 |
1107 let logmap = |Timed { cpu_time, iter, data }| { |
1178 let logmap = |Timed { cpu_time, iter, data }| { |
1108 let IterInfo { |
1179 let IterInfo { |
1109 value, |
1180 value, |
1110 n_spikes, |
1181 n_spikes, |