diff options
author | Minijackson <minijackson@riseup.net> | 2022-12-22 12:19:59 +0100 |
---|---|---|
committer | Minijackson <minijackson@riseup.net> | 2022-12-22 12:19:59 +0100 |
commit | 92a02c34628343153b33602eae00cef46e28d191 (patch) | |
tree | 8622ec528d24e456be22d984d93aa9bcafc97399 /core/src/solving.rs | |
download | diaphragm-92a02c34628343153b33602eae00cef46e28d191.tar.gz diaphragm-92a02c34628343153b33602eae00cef46e28d191.zip |
WIP
Diffstat (limited to 'core/src/solving.rs')
-rw-r--r-- | core/src/solving.rs | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/core/src/solving.rs b/core/src/solving.rs new file mode 100644 index 0000000..c7e94ba --- /dev/null +++ b/core/src/solving.rs | |||
@@ -0,0 +1,279 @@ | |||
1 | use super::core_shapes::*; | ||
2 | use super::styles::*; | ||
3 | use super::text::*; | ||
4 | use super::types::{Bool, Float}; | ||
5 | |||
6 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||
7 | pub struct VariableHandle(usize); | ||
8 | |||
9 | impl VariableHandle { | ||
10 | pub fn new(id: usize) -> Self { | ||
11 | Self(id) | ||
12 | } | ||
13 | |||
14 | pub fn id(&self) -> usize { | ||
15 | self.0 | ||
16 | } | ||
17 | } | ||
18 | |||
19 | /* | ||
20 | pub trait VariableFloat<'a> { | ||
21 | fn id(&self) -> usize; | ||
22 | fn dyn_clone(&self) -> Box<dyn VariableFloat<'a> + 'a>; | ||
23 | |||
24 | fn eq(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
25 | fn neq(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
26 | fn gt(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
27 | fn ge(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
28 | fn lt(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
29 | fn le(&self, other: &dyn VariableFloat) -> Bool<'a>; | ||
30 | |||
31 | fn add(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
32 | fn sub(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
33 | fn mul(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
34 | fn div(&self, other: &dyn VariableFloat) -> Float<'a>; | ||
35 | |||
36 | fn neg(&self) -> Float<'a>; | ||
37 | } | ||
38 | |||
39 | pub trait VariableBool<'a> { | ||
40 | fn id(&self) -> usize; | ||
41 | fn dyn_clone(&self) -> Box<dyn VariableBool<'a> + 'a>; | ||
42 | |||
43 | fn eq(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
44 | fn neq(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
45 | |||
46 | fn and(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
47 | fn or(&self, other: &dyn VariableBool) -> Bool<'a>; | ||
48 | |||
49 | fn not(&self) -> Bool<'a>; | ||
50 | } | ||
51 | */ | ||
52 | |||
53 | pub trait SolverContext { | ||
54 | fn solve<'a>(&'a self) -> Box<dyn SolverModel + 'a>; | ||
55 | fn constrain(&mut self, assertion: Bool); | ||
56 | |||
57 | // Floats | ||
58 | |||
59 | fn new_free_float(&mut self) -> Float; | ||
60 | fn new_fixed_float(&mut self, value: f64) -> Float; | ||
61 | |||
62 | fn float_add(&mut self, values: &[Float]) -> Float; | ||
63 | fn float_sub(&mut self, values: &[Float]) -> Float; | ||
64 | fn float_mul(&mut self, values: &[Float]) -> Float; | ||
65 | fn float_div(&mut self, lhs: Float, rhs: Float) -> Float; | ||
66 | fn float_neg(&mut self, value: Float) -> Float; | ||
67 | |||
68 | fn float_eq(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
69 | fn float_ne(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
70 | fn float_gt(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
71 | fn float_ge(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
72 | fn float_lt(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
73 | fn float_le(&mut self, lhs: Float, rhs: Float) -> Bool; | ||
74 | |||
75 | fn float_max(&mut self, values: &[Float]) -> Float { | ||
76 | let result = self.new_free_float(); | ||
77 | |||
78 | for (index, &candidate) in values.iter().enumerate() { | ||
79 | let comparisons: Vec<_> = values | ||
80 | .iter() | ||
81 | .enumerate() | ||
82 | .filter(|(other_index, _)| *other_index != index) | ||
83 | .map(|(_, &other)| self.float_ge(candidate, other)) | ||
84 | .collect(); | ||
85 | |||
86 | let premise = self.bool_and(&comparisons); | ||
87 | let conclusion = self.float_eq(candidate, result); | ||
88 | let implication = self.bool_implies(premise, conclusion); | ||
89 | self.constrain(implication); | ||
90 | } | ||
91 | |||
92 | result | ||
93 | } | ||
94 | |||
95 | fn float_min(&mut self, values: &[Float]) -> Float { | ||
96 | let result = self.new_free_float(); | ||
97 | |||
98 | for (index, &candidate) in values.iter().enumerate() { | ||
99 | let comparisons: Vec<_> = values | ||
100 | .iter() | ||
101 | .enumerate() | ||
102 | .filter(|(other_index, _)| *other_index != index) | ||
103 | .map(|(_, &other)| self.float_le(candidate, other)) | ||
104 | .collect(); | ||
105 | |||
106 | let premise = self.bool_and(&comparisons); | ||
107 | let conclusion = self.float_eq(candidate, result); | ||
108 | let implication = self.bool_implies(premise, conclusion); | ||
109 | self.constrain(implication); | ||
110 | } | ||
111 | |||
112 | result | ||
113 | } | ||
114 | |||
115 | // Bools | ||
116 | |||
117 | fn new_free_bool(&mut self) -> Bool; | ||
118 | fn new_fixed_bool(&mut self, value: bool) -> Bool; | ||
119 | |||
120 | fn bool_eq(&mut self, lhs: Bool, rhs: Bool) -> Bool; | ||
121 | fn bool_ne(&mut self, lhs: Bool, rhs: Bool) -> Bool; | ||
122 | |||
123 | fn bool_and(&mut self, values: &[Bool]) -> Bool; | ||
124 | fn bool_or(&mut self, values: &[Bool]) -> Bool; | ||
125 | fn bool_not(&mut self, value: Bool) -> Bool; | ||
126 | |||
127 | fn bool_implies(&mut self, lhs: Bool, rhs: Bool) -> Bool; | ||
128 | } | ||
129 | |||
130 | pub trait SolverModel { | ||
131 | fn eval_float(&self, f: Float) -> Option<f64>; | ||
132 | fn eval_bool(&self, b: Bool) -> Option<bool>; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | pub trait Solver { | ||
137 | fn constrain(&mut self, assertion: &Bool); | ||
138 | fn solve(&self) -> Box<dyn SolverModel>; | ||
139 | } | ||
140 | */ | ||
141 | |||
142 | use super::types::*; | ||
143 | |||
144 | pub trait Constrainable { | ||
145 | type Fixated; | ||
146 | |||
147 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated>; | ||
148 | } | ||
149 | |||
150 | impl Constrainable for Float { | ||
151 | type Fixated = f64; | ||
152 | |||
153 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
154 | model.eval_float(*self) | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | fn fixate(&self, model: &Model) -> Self::Fixated { | ||
159 | match self { | ||
160 | Float::Defined(float) => *float, | ||
161 | Float::Constrained(variable) => { | ||
162 | let (num, den) = model | ||
163 | .eval::<z3::ast::Real>(variable) | ||
164 | .expect("Couldn't eval variable") | ||
165 | .as_real() | ||
166 | .expect("Couldn't get value from variable"); | ||
167 | |||
168 | num as f64 / den as f64 | ||
169 | } | ||
170 | Float::Undefined => panic!("Undefined float"), | ||
171 | } | ||
172 | } | ||
173 | */ | ||
174 | } | ||
175 | |||
176 | impl Constrainable for Bounds { | ||
177 | type Fixated = DefinedBounds; | ||
178 | |||
179 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
180 | Some(DefinedBounds { | ||
181 | top: self.top.fixate(model)?, | ||
182 | left: self.left.fixate(model)?, | ||
183 | width: self.width.fixate(model)?, | ||
184 | height: self.height.fixate(model)?, | ||
185 | }) | ||
186 | } | ||
187 | } | ||
188 | |||
189 | impl Constrainable for StrokeStyle { | ||
190 | type Fixated = DefinedStrokeStyle; | ||
191 | |||
192 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
193 | let dash = match &self.dash { | ||
194 | Some(dash) => Some(dash.fixate(model)?), | ||
195 | None => None, | ||
196 | }; | ||
197 | |||
198 | Some(DefinedStrokeStyle { | ||
199 | pattern: self.pattern.clone(), | ||
200 | dash, | ||
201 | line_width: self.line_width.fixate(model)?, | ||
202 | }) | ||
203 | } | ||
204 | } | ||
205 | |||
206 | impl Constrainable for DashStyle { | ||
207 | type Fixated = DefinedDashStyle; | ||
208 | |||
209 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
210 | Some(DefinedDashStyle { | ||
211 | dashes: self | ||
212 | .dashes | ||
213 | .iter() | ||
214 | .map(|value| value.fixate(model)) | ||
215 | .collect::<Option<_>>()?, | ||
216 | offset: self.offset.fixate(model)?, | ||
217 | }) | ||
218 | } | ||
219 | } | ||
220 | |||
221 | impl Constrainable for ShapeContext { | ||
222 | type Fixated = DefinedShapeContext; | ||
223 | |||
224 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
225 | Some(DefinedShapeContext { | ||
226 | bounds: self.bounds.fixate(model)?, | ||
227 | fill: self.fill.clone(), | ||
228 | stroke: self.stroke.fixate(model)?, | ||
229 | }) | ||
230 | } | ||
231 | } | ||
232 | |||
233 | impl Constrainable for Point2D { | ||
234 | type Fixated = DefinedPoint2D; | ||
235 | |||
236 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
237 | Some(DefinedPoint2D { | ||
238 | x: self.x.fixate(model)?, | ||
239 | y: self.y.fixate(model)?, | ||
240 | }) | ||
241 | } | ||
242 | } | ||
243 | |||
244 | impl Constrainable for FontDescription { | ||
245 | type Fixated = DefinedFontDescription; | ||
246 | |||
247 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
248 | Some(DefinedFontDescription { | ||
249 | family: self.family.clone(), | ||
250 | style: self.style, | ||
251 | weight: self.weight, | ||
252 | size: self.size.fixate(&*model)?, | ||
253 | }) | ||
254 | } | ||
255 | } | ||
256 | |||
257 | impl Constrainable for Text { | ||
258 | type Fixated = DefinedText; | ||
259 | |||
260 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
261 | Some(DefinedText { | ||
262 | content: self.content.clone(), | ||
263 | font: self.font.fixate(&*model)?, | ||
264 | }) | ||
265 | } | ||
266 | } | ||
267 | |||
268 | impl Constrainable for StraightPath { | ||
269 | type Fixated = DefinedStraightPath; | ||
270 | |||
271 | fn fixate(&self, model: &dyn SolverModel) -> Option<Self::Fixated> { | ||
272 | let points: Option<_> = self | ||
273 | .points | ||
274 | .iter() | ||
275 | .map(|point| point.fixate(model)) | ||
276 | .collect(); | ||
277 | Some(DefinedStraightPath { points: points? }) | ||
278 | } | ||
279 | } | ||