laddu_core/parameters/
parameter.rs1use std::{hash::Hash, sync::Arc};
4
5use parking_lot::Mutex;
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Default, Serialize, Deserialize, Debug)]
9struct ParameterMetadata {
10 name: String,
12 fixed: Option<f64>,
14 initial: Option<f64>,
17 bounds: (Option<f64>, Option<f64>),
20 unit: Option<String>,
22 latex: Option<String>,
24 description: Option<String>,
26}
27
28#[derive(Clone, Default, Serialize, Deserialize, Debug)]
30pub struct Parameter(Arc<Mutex<ParameterMetadata>>);
31
32impl PartialEq for Parameter {
33 fn eq(&self, other: &Self) -> bool {
34 self.0.lock().name == other.0.lock().name
35 }
36}
37impl Eq for Parameter {}
38impl Hash for Parameter {
39 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
40 self.0.lock().name.hash(state);
41 }
42}
43
44pub trait IntoBound {
46 fn into_bound(self) -> Option<f64>;
48}
49impl IntoBound for f64 {
50 fn into_bound(self) -> Option<f64> {
51 Some(self)
52 }
53}
54impl IntoBound for Option<f64> {
55 fn into_bound(self) -> Option<f64> {
56 self
57 }
58}
59
60impl Parameter {
61 pub fn new(name: impl Into<String>) -> Self {
63 Self(Arc::new(Mutex::new(ParameterMetadata {
64 name: name.into(),
65 ..Default::default()
66 })))
67 }
68
69 pub fn new_fixed(name: impl Into<String>, value: f64) -> Self {
71 Self(Arc::new(Mutex::new(ParameterMetadata {
72 name: name.into(),
73 fixed: Some(value),
74 ..Default::default()
75 })))
76 }
77
78 pub fn name(&self) -> String {
80 self.0.lock().name.clone()
81 }
82
83 pub fn fixed(&self) -> Option<f64> {
85 self.0.lock().fixed
86 }
87
88 pub fn initial(&self) -> Option<f64> {
90 self.0.lock().initial
91 }
92
93 pub fn bounds(&self) -> (Option<f64>, Option<f64>) {
95 self.0.lock().bounds
96 }
97
98 pub fn unit(&self) -> Option<String> {
100 self.0.lock().unit.clone()
101 }
102
103 pub fn latex(&self) -> Option<String> {
105 self.0.lock().latex.clone()
106 }
107
108 pub fn description(&self) -> Option<String> {
110 self.0.lock().description.clone()
111 }
112
113 pub(crate) fn set_name(&self, name: impl Into<String>) {
115 self.0.lock().name = name.into();
116 }
117
118 pub fn set_fixed_value(&self, value: Option<f64>) {
120 let mut guard = self.0.lock();
121 if let Some(value) = value {
122 guard.fixed = Some(value);
123 guard.initial = Some(value);
124 } else {
125 guard.fixed = None;
126 }
127 }
128
129 pub fn set_initial(&self, value: f64) {
135 assert!(
136 self.is_free(),
137 "cannot manually set `initial` on a fixed parameter"
138 );
139 self.0.lock().initial = Some(value);
140 }
141
142 pub fn set_bounds<L, U>(&self, min: L, max: U)
144 where
145 L: IntoBound,
146 U: IntoBound,
147 {
148 self.0.lock().bounds = (IntoBound::into_bound(min), IntoBound::into_bound(max));
149 }
150
151 pub fn set_unit(&self, unit: impl Into<String>) {
153 self.0.lock().unit = Some(unit.into());
154 }
155
156 pub fn set_latex(&self, latex: impl Into<String>) {
158 self.0.lock().latex = Some(latex.into());
159 }
160
161 pub fn set_description(&self, description: impl Into<String>) {
163 self.0.lock().description = Some(description.into());
164 }
165
166 pub fn is_free(&self) -> bool {
168 self.0.lock().fixed.is_none()
169 }
170
171 pub fn is_fixed(&self) -> bool {
173 self.0.lock().fixed.is_some()
174 }
175}
176
177#[macro_export]
180macro_rules! parameter {
181 ($name:expr) => {{
182 $crate::parameters::Parameter::new($name)
183 }};
184
185 ($name:expr, $value:expr) => {{
186 let p = $crate::parameters::Parameter::new($name);
187 p.set_fixed_value(Some($value));
188 p
189 }};
190
191 ($name:expr, $($rest:tt)+) => {{
192 let p = $crate::parameters::Parameter::new($name);
193 $crate::parameter!(@parse p, [fixed = false, initial = false]; $($rest)+);
194 p
195 }};
196
197 (@parse $p:ident, [fixed = $f:tt, initial = $i:tt]; ) => {};
198
199 (@parse $p:ident, [fixed = false, initial = false]; fixed : $value:expr $(, $($rest:tt)*)?) => {{
200 $p.set_fixed_value(Some($value));
201 $crate::parameter!(@parse $p, [fixed = true, initial = false]; $($($rest)*)?);
202 }};
203
204 (@parse $p:ident, [fixed = false, initial = false]; initial : $value:expr $(, $($rest:tt)*)?) => {{
205 $p.set_initial($value);
206 $crate::parameter!(@parse $p, [fixed = false, initial = true]; $($($rest)*)?);
207 }};
208
209 (@parse $p:ident, [fixed = true, initial = false]; initial : $value:expr $(, $($rest:tt)*)?) => {
210 compile_error!("parameter!: cannot specify both `fixed` and `initial`");
211 };
212
213 (@parse $p:ident, [fixed = false, initial = true]; fixed : $value:expr $(, $($rest:tt)*)?) => {
214 compile_error!("parameter!: cannot specify both `fixed` and `initial`");
215 };
216
217 (@parse $p:ident, [fixed = $f:tt, initial = $i:tt]; bounds : ($min:expr, $max:expr) $(, $($rest:tt)*)?) => {{
218 $p.set_bounds($min, $max);
219 $crate::parameter!(@parse $p, [fixed = $f, initial = $i]; $($($rest)*)?);
220 }};
221
222 (@parse $p:ident, [fixed = $f:tt, initial = $i:tt]; unit : $value:expr $(, $($rest:tt)*)?) => {{
223 $p.set_unit($value);
224 $crate::parameter!(@parse $p, [fixed = $f, initial = $i]; $($($rest)*)?);
225 }};
226
227 (@parse $p:ident, [fixed = $f:tt, initial = $i:tt]; latex : $value:expr $(, $($rest:tt)*)?) => {{
228 $p.set_latex($value);
229 $crate::parameter!(@parse $p, [fixed = $f, initial = $i]; $($($rest)*)?);
230 }};
231
232 (@parse $p:ident, [fixed = $f:tt, initial = $i:tt]; description : $value:expr $(, $($rest:tt)*)?) => {{
233 $p.set_description($value);
234 $crate::parameter!(@parse $p, [fixed = $f, initial = $i]; $($($rest)*)?);
235 }};
236}