geo_aid_internal/engine/compiler.rs
1//! This module contains functionality to compile Math IR
2//! into Geo-AID's math backend IR, the last step before
3//! compiling to the final form. The final step is performed
4//! by the `geo-aid-math` crate.
5
6use crate::geometry::{Circle, Complex, Line, ValueEnum};
7use crate::script::figure::Generated;
8use crate::script::math::{
9 Entity, EntityKind, Expr, ExprKind, ExprType, Intermediate, Rule, RuleKind,
10};
11use geo_aid_figure::{EntityIndex, VarIndex};
12use geo_aid_math::shared::Shared;
13use geo_aid_math::{
14 shared::Complex as ComplexExpr, shared::Real as RealExpr, Comparison, ComparisonKind,
15 Condition, Context,
16};
17use num_traits::ToPrimitive;
18use std::f64::consts::PI;
19
20/// A function that takes in values for all inputs and returns
21/// a generated figure
22pub type FigureFn = Box<dyn for<'a> Fn(&'a [f64]) -> Generated>;
23
24/// The result of the compilation of a Math IR.
25pub struct Compiled {
26 /// The figure function
27 pub figure_fn: FigureFn,
28 /// Errors of each adjustable
29 pub errors: Vec<RealExpr>,
30 /// The compile context. Can be used for further processing
31 pub context: Shared,
32 /// The number of inputs of this figure.
33 pub input_count: usize,
34 /// Errors of each rule (for debugging purposes)
35 #[allow(unused)]
36 pub rule_errors: Vec<RealExpr>,
37}
38
39/// Compile a Math IR into an (almost) compiled form.
40#[must_use]
41pub fn compile(intermediate: &Intermediate) -> Compiled {
42 let inputs = intermediate
43 .adjusted
44 .entities
45 .iter()
46 .map(|ent| match ent {
47 EntityKind::FreePoint => 2,
48 EntityKind::PointOnLine { .. }
49 | EntityKind::PointOnCircle { .. }
50 | EntityKind::FreeReal
51 | EntityKind::DistanceUnit => 1,
52 EntityKind::Bind(_) => unreachable!(),
53 })
54 .sum();
55
56 // for (i, var) in intermediate.figure.variables.iter().enumerate() {
57 // println!("[{i}] = {:?}", var.kind);
58 // }
59
60 // We start with constructing the figure function.
61
62 let mut compiler = Compiler::new(
63 inputs,
64 &intermediate.adjusted.entities,
65 &intermediate.figure.variables,
66 );
67
68 // Collect all expressions necessary for figure drawing.
69
70 // Including the entities
71 let mut entity_values = Vec::new();
72 for (i, ent) in intermediate.figure.entities.iter().enumerate() {
73 let v = Expr {
74 meta: (),
75 kind: ExprKind::Entity { id: EntityIndex(i) },
76 ty: match ent {
77 EntityKind::FreePoint
78 | EntityKind::PointOnLine { line: _ }
79 | EntityKind::PointOnCircle { circle: _ } => ExprType::Point,
80 EntityKind::FreeReal | EntityKind::DistanceUnit => ExprType::Number,
81 EntityKind::Bind(_) => unreachable!(),
82 },
83 };
84
85 entity_values.push(compiler.compile_value(&v));
86 }
87
88 let mut exprs = Vec::new();
89 for value in compiler.variables.iter().chain(&entity_values) {
90 match value {
91 ValueExpr::This(this) => exprs.push(this.expr),
92 ValueExpr::Line(line) => exprs.extend([
93 line.origin.real.expr,
94 line.origin.imaginary.expr,
95 line.direction.real.expr,
96 line.direction.imaginary.expr,
97 ]),
98 ValueExpr::Complex(complex) => {
99 exprs.extend([complex.real.expr, complex.imaginary.expr]);
100 }
101 ValueExpr::Circle(circle) => {
102 exprs.extend([
103 circle.center.real.expr,
104 circle.center.imaginary.expr,
105 circle.radius.expr,
106 ]);
107 }
108 }
109 }
110
111 let outs_len = exprs.len();
112 let exprs = compiler.context.exec(|ctx| ctx.compute(exprs));
113 let fig = intermediate.figure.clone();
114 let figure_fn = Box::new(move |inputs: &[f64]| {
115 let mut outputs = Vec::new();
116 outputs.resize(outs_len, 0.0);
117 exprs.call(inputs, outputs.as_mut_slice());
118
119 get_figure(&fig, &outputs)
120 });
121
122 // Reset the compiler and gather rule errors.
123 compiler = Compiler::new(
124 inputs,
125 &intermediate.adjusted.entities,
126 &intermediate.adjusted.variables,
127 );
128 let rule_errors: Vec<_> = intermediate
129 .adjusted
130 .rules
131 .iter()
132 .map(|rule| (rule, compiler.compile_rule(rule)))
133 .collect();
134
135 let rule_error_exprs = rule_errors.iter().map(|v| v.1.clone()).collect();
136
137 // Gather entity errors
138 let mut entity_errors: Vec<_> = (0..intermediate.adjusted.entities.len())
139 .map(|_| compiler.context.real_zero())
140 .collect();
141 for (rule, quality) in rule_errors {
142 // println!("{rule}");
143 for ent in &rule.entities {
144 entity_errors[ent.0] += &quality;
145 }
146 }
147
148 // For now, this is how we calculate errors
149
150 Compiled {
151 figure_fn,
152 errors: entity_errors,
153 context: compiler.context,
154 input_count: inputs,
155 rule_errors: rule_error_exprs,
156 }
157}
158
159/// The compiler's state
160struct Compiler<'r> {
161 entities: &'r [EntityKind],
162 context: Shared,
163 variables: Vec<ValueExpr>,
164 adjustables: Vec<ValueExpr>,
165}
166
167impl<'r> Compiler<'r> {
168 /// Create a new compiler. Prepares some constants and precomputes all values.
169 #[must_use]
170 pub fn new(inputs: usize, entities: &'r [EntityKind], variables: &[Expr<()>]) -> Self {
171 let mut adjustables = Vec::new();
172 let context = Shared::new(inputs);
173
174 let mut index = 0;
175 #[allow(unused_variables)]
176 for (i, ent) in entities.iter().enumerate() {
177 // println!("@[{i}] = {ent:?}");
178 match ent {
179 EntityKind::FreePoint => {
180 adjustables.push(ValueExpr::Complex(ComplexExpr {
181 real: context.input(index),
182 imaginary: context.input(index + 1),
183 }));
184 index += 2;
185 }
186 EntityKind::PointOnLine { .. }
187 | EntityKind::PointOnCircle { .. }
188 | EntityKind::FreeReal
189 | EntityKind::DistanceUnit => {
190 adjustables.push(ValueExpr::This(context.input(index)));
191 index += 1;
192 }
193 EntityKind::Bind(_) => unreachable!(),
194 }
195 }
196
197 let mut s = Self {
198 entities,
199 context,
200 variables: Vec::new(),
201 adjustables,
202 };
203
204 #[allow(unused_variables)]
205 for (i, var) in variables.iter().enumerate() {
206 // println!("[{i}] = {:?}", var.kind);
207 let expr = s.compile_value(var);
208 s.variables.push(expr);
209 }
210
211 s
212 }
213
214 /// Compile the error function for a > b
215 fn gt(&mut self, a: &VarIndex, b: &VarIndex) -> RealExpr {
216 let a = self.variables[a.0].to_complex().real;
217 let b = self.variables[b.0].to_complex().real;
218 let one_tenth = self.context.constant(0.1);
219 let offset = (b.abs() + &one_tenth) * &one_tenth;
220 let threshold = b + &offset;
221 let a_minus_threshold = a.clone() - &threshold;
222 let one_side = a_minus_threshold.clone() * &a_minus_threshold;
223 self.context.ternary(
224 Condition::Comparison(Comparison {
225 a: threshold.expr,
226 b: a.expr,
227 kind: ComparisonKind::Gt,
228 }),
229 one_side,
230 self.context.real_zero(),
231 )
232 }
233
234 /// Compile the error function for the given rule kind.
235 fn compile_rule_kind(&mut self, kind: &RuleKind) -> RealExpr {
236 match kind {
237 RuleKind::PointEq(a, b) | RuleKind::NumberEq(a, b) => {
238 // Weirdly, enough, these two are actually the same, right now
239 let a = self.variables[a.0].to_complex();
240 let b = self.variables[b.0].to_complex();
241 let five = self.context.constant(5.0);
242 (a - &b).norm() * &five
243 }
244 RuleKind::Gt(a, b) => self.gt(a, b),
245 RuleKind::Alternative(rules) => {
246 // necessary because borrowing
247 let qualities: Vec<_> = rules
248 .iter()
249 .map(|rule| self.compile_rule_kind(rule))
250 .collect();
251
252 qualities.into_iter().reduce(|a, b| a.min(&b)).unwrap()
253 }
254 RuleKind::Invert(q) => {
255 self.context.real_one()
256 / &(self.context.constant(10.0) * &self.compile_rule_kind(q))
257 }
258 RuleKind::Bias => self.context.real_zero(), // Bias in this approach doesn't really do anything
259 }
260 }
261
262 /// Compile the error function for the given rule.
263 fn compile_rule(&mut self, rule: &Rule) -> RealExpr {
264 let quality = self.compile_rule_kind(&rule.kind);
265 let weight = self.context.constant(rule.weight.to_complex().real);
266 quality * &weight
267 }
268
269 /// Compile the sum of given expressions.
270 fn compile_sum(&mut self, value: &[VarIndex]) -> ComplexExpr {
271 value
272 .iter()
273 .map(|i| self.variables[i.0].to_complex())
274 .reduce(|a, b| a + &b)
275 .unwrap_or(self.context.complex_zero())
276 }
277
278 /// Compile the product of different expressions
279 fn compile_mul(&mut self, value: &[VarIndex]) -> ComplexExpr {
280 value
281 .iter()
282 .map(|i| self.variables[i.0].to_complex())
283 .reduce(|a, b| a * &b)
284 .unwrap_or(self.context.complex_one())
285 }
286
287 /// Compile the specific expression.
288 /// Assume all expressions it may depend on are already compiled.
289 /// This assumption is true given that expressions are processed
290 /// one by one, in a preordered fashion.
291 #[allow(clippy::too_many_lines)]
292 fn compile_value(&mut self, value: &Expr<()>) -> ValueExpr {
293 match &value.kind {
294 ExprKind::Entity { id } => {
295 let kind = self.entities[id.0].clone();
296 match kind {
297 EntityKind::FreePoint => self.adjustables[id.0].clone(),
298 EntityKind::PointOnLine { line } => {
299 let line = self.variables[line.0].to_line();
300 let offset = self.adjustables[id.0].to_single();
301
302 (line.origin + &(offset * &line.direction)).into()
303 }
304 EntityKind::PointOnCircle { circle } => {
305 let circle = self.variables[circle.0].to_circle();
306 let theta = self.adjustables[id.0].to_single();
307 let two_pi = self.context.constant(2.0 * PI);
308 let theta = theta * &two_pi;
309
310 let point_rel = ComplexExpr {
311 real: theta.cos(),
312 imaginary: theta.sin(),
313 } * &circle.radius;
314
315 (point_rel + &circle.center).into()
316 }
317 EntityKind::DistanceUnit | EntityKind::FreeReal => {
318 ComplexExpr::real(self.adjustables[id.0].to_single()).into()
319 }
320 EntityKind::Bind(_) => unreachable!(),
321 }
322 }
323 ExprKind::LineLineIntersection { k, l } => {
324 // This is the code in geometry.rs
325 // let Line {
326 // origin: a,
327 // direction: b,
328 // } = k_ln;
329 // let Line {
330 // origin: c,
331 // direction: d,
332 // } = l_ln;
333 //
334 // a - b * ((a - c) / d).imaginary / (b / d).imaginary
335 // println!("Broke with k={k}, l={l}");
336 // println!("{:#?}", self.variables);
337 let k = self.variables[k.0].to_line();
338 let l = self.variables[l.0].to_line();
339 // a = k.origin;
340 // b = k.direction;
341 // c = l.origin;
342 // d = l.direction;
343
344 let b_by_d = k.direction.clone() / &l.direction;
345 let a_sub_c = k.origin.clone() - &l.origin;
346 let a_sub_c_by_d = a_sub_c / &l.direction;
347 let quotient = a_sub_c_by_d.imaginary / &b_by_d.imaginary;
348 let b_times_quotient = k.direction * "ient;
349
350 (k.origin - &b_times_quotient).into()
351 }
352 ExprKind::AveragePoint { items } => {
353 let sum = self.compile_sum(items);
354
355 #[allow(clippy::cast_precision_loss)]
356 let len = self.context.constant(items.len() as f64);
357 (sum / &len).into()
358 }
359 ExprKind::CircleCenter { circle } => self.variables[circle.0].to_circle().center.into(),
360 ExprKind::ComplexToPoint { number } => self.variables[number.0].clone(),
361 ExprKind::Sum { plus, minus } => {
362 (self.compile_sum(plus) - &self.compile_sum(minus)).into()
363 }
364 ExprKind::Product { times, by } => {
365 (self.compile_mul(times) / &self.compile_mul(by)).into()
366 }
367 ExprKind::Const { value } => {
368 let value = value.to_complex();
369 ComplexExpr {
370 real: self.context.constant(value.real),
371 imaginary: self.context.constant(value.imaginary),
372 }
373 .into()
374 }
375 ExprKind::Exponentiation { value, exponent } => {
376 let value = self.variables[value.0].to_complex();
377 let exp = self.context.constant(exponent.to_f64().unwrap());
378
379 value.pow(&ComplexExpr::real(exp)).into()
380 }
381 ExprKind::PointPointDistance { p, q } => {
382 let p = self.variables[p.0].to_complex();
383 let q = self.variables[q.0].to_complex();
384
385 ComplexExpr::real((p - &q).abs()).into()
386 }
387 ExprKind::PointLineDistance { point, line } => {
388 // ((point - line.origin) / line.direction).imaginary.abs()
389 let point = self.variables[point.0].to_complex();
390 let line = self.variables[line.0].to_line();
391
392 ComplexExpr::real(((point - &line.origin) / &line.direction).imaginary.abs()).into()
393 }
394 ExprKind::ThreePointAngle { p, q, r } => {
395 // geometry.rs code
396 // let arm1_vec = arm1 - origin;
397 // let arm2_vec = arm2 - origin;
398 //
399 // // Get the dot product
400 // let dot_product = arm1_vec.real * arm2_vec.real + arm1_vec.imaginary * arm2_vec.imaginary;
401 //
402 // // Get the argument
403 // f64::acos(dot_product / (arm1_vec.magnitude() * arm2_vec.magnitude()))
404 let p = self.variables[p.0].to_complex();
405 let q = self.variables[q.0].to_complex();
406 let r = self.variables[r.0].to_complex();
407
408 let arm1_vec = p - &q;
409 let arm2_vec = r - &q;
410
411 let mag_product = arm1_vec.abs() * &arm2_vec.abs();
412 let dot_product_alpha = arm1_vec.real * &arm2_vec.real;
413 let dot_product_beta = arm1_vec.imaginary * &arm2_vec.imaginary;
414 let dot_product = dot_product_alpha + &dot_product_beta;
415 let quotient = dot_product / &mag_product;
416 ComplexExpr::real(quotient.acos()).into()
417 }
418 ExprKind::ThreePointAngleDir { p, q, r } => {
419 // geometry.rs code
420 // Get the vectors to calculate the angle between them.
421 // let arm1_vec = arm1 - origin;
422 // let arm2_vec = arm2 - origin;
423 //
424 // // decrease p2's angle by p1's angle:
425 // let p2_rotated = arm2_vec / arm1_vec;
426 //
427 // // Get the argument
428 // p2_rotated.arg()
429 let p = self.variables[p.0].to_complex();
430 let q = self.variables[q.0].to_complex();
431 let r = self.variables[r.0].to_complex();
432
433 let arm1_vec = p - &q;
434 let arm2_vec = r - &q;
435
436 let rotated = arm2_vec / &arm1_vec;
437 ComplexExpr::real(rotated.arg()).into()
438 }
439 ExprKind::TwoLineAngle { k, l } => {
440 // (k.direction / l.direction).arg().abs()
441 let k = self.variables[k.0].to_line();
442 let l = self.variables[l.0].to_line();
443 let quotient = k.direction / &l.direction;
444 ComplexExpr::real(quotient.arg().abs()).into()
445 }
446 ExprKind::PointX { point } => {
447 let point = self.variables[point.0].to_complex();
448 ComplexExpr::real(point.real).into()
449 }
450 ExprKind::PointY { point } => {
451 let point = self.variables[point.0].to_complex();
452 ComplexExpr::real(point.imaginary).into()
453 }
454 ExprKind::PointToComplex { point } => self.variables[point.0].clone(),
455 ExprKind::Real { number } => {
456 ComplexExpr::real(self.variables[number.0].to_complex().real).into()
457 }
458 ExprKind::Imaginary { number } => {
459 ComplexExpr::real(self.variables[number.0].to_complex().imaginary).into()
460 }
461 ExprKind::Log { number } => self.variables[number.0].to_complex().log().into(),
462 ExprKind::Exp { number } => self.variables[number.0].to_complex().exp().into(),
463 ExprKind::Sin { angle } => {
464 let angle = self.variables[angle.0].to_complex();
465 angle.sin().into()
466 }
467 ExprKind::Cos { angle } => {
468 let angle = self.variables[angle.0].to_complex();
469 angle.cos().into()
470 }
471 ExprKind::Atan2 { y, x } => {
472 // Atan2 is never expected to take complex arguments.
473 let y = self.variables[y.0].to_complex().real;
474 let x = self.variables[x.0].to_complex().real;
475
476 ComplexExpr::real(RealExpr::atan2(&y, &x)).into()
477 }
478 ExprKind::DirectionVector { line } => self.variables[line.0].to_line().direction.into(),
479 ExprKind::PointPoint { p, q } => {
480 let p = self.variables[p.0].to_complex();
481 let q = self.variables[q.0].to_complex();
482 let q_minus_p = q - &p;
483 LineExpr {
484 origin: p,
485 direction: q_minus_p.clone() / &q_minus_p.abs(),
486 }
487 .into()
488 }
489 ExprKind::PointVector { point, vector } => {
490 let point = self.variables[point.0].to_complex();
491 let vector = self.variables[vector.0].to_complex();
492
493 LineExpr {
494 origin: point,
495 direction: vector.clone() / &vector.abs(),
496 }
497 .into()
498 }
499 ExprKind::AngleBisector { p, q, r } => {
500 // let a = arm1 - origin;
501 // let b = arm2 - origin;
502 //
503 // // Get the bisector using the geometric mean.
504 // let bi_dir = (a * b).sqrt_norm();
505 //
506 // Line::new(origin, bi_dir)
507 //
508 // Where sqrt_norm looks like this:
509 // // The formula used here doesn't work for negative reals. We can use a trick here to bypass that restriction.
510 // // If the real part is negative, we simply negate it to get a positive part and then multiply the result by `i`.
511 // if self.real > 0.0 {
512 // // Use the generic formula (https://math.stackexchange.com/questions/44406/how-do-i-get-the-square-root-of-a-complex-number)
513 // let r = self.magnitude();
514 //
515 // // We simply don't multiply by the square root of r.
516 // (self + r).normalize()
517 // } else {
518 // (-self).sqrt_norm().mul_i() // Normalization isn't lost here.
519 // }
520 let arm1 = self.variables[p.0].to_complex();
521 let origin = self.variables[q.0].to_complex();
522 let arm2 = self.variables[r.0].to_complex();
523
524 let ab = (arm1 - &origin) * &(arm2 - &origin);
525
526 // sqrt_norm time
527 let minus_ab = -ab.clone();
528
529 let condition = Condition::Comparison(Comparison {
530 a: ab.real.expr,
531 b: Context::zero(),
532 kind: ComparisonKind::Gt,
533 });
534 let self_ = self.context.complex_ternary(condition, ab, minus_ab);
535
536 let self_plus_r = self_.clone() + &self_.abs();
537 let normalized = self_plus_r.clone() / &self_plus_r.abs();
538 let normalized_mul_i = normalized.mul_i();
539
540 // Another ternary
541 let direction =
542 self.context
543 .complex_ternary(condition, normalized, normalized_mul_i);
544
545 LineExpr { origin, direction }.into()
546 }
547 ExprKind::ParallelThrough { point, line } => {
548 let point = self.variables[point.0].to_complex();
549 let mut line = self.variables[line.0].to_line();
550
551 line.origin = point;
552 line.into()
553 }
554 ExprKind::PerpendicularThrough { point, line } => {
555 let point = self.variables[point.0].to_complex();
556 let line = self.variables[line.0].to_line();
557
558 LineExpr {
559 origin: point,
560 direction: line.direction.mul_i(),
561 }
562 .into()
563 }
564 ExprKind::ConstructCircle { center, radius } => {
565 let center = self.variables[center.0].to_complex();
566 let radius = self.variables[radius.0].to_complex();
567
568 CircleExpr {
569 center,
570 radius: radius.real,
571 }
572 .into()
573 }
574 }
575 }
576}
577
578/// A generic compiled value of an expression.
579#[derive(Debug, Clone)]
580enum ValueExpr {
581 This(RealExpr),
582 Line(LineExpr),
583 Complex(ComplexExpr),
584 Circle(CircleExpr),
585}
586
587impl ValueExpr {
588 /// Returns a line if the expression is one. Panics otherwise.
589 #[must_use]
590 fn to_line(&self) -> LineExpr {
591 if let Self::Line(x) = self {
592 x.clone()
593 } else {
594 panic!("self was not a line");
595 }
596 }
597
598 /// Returns a point if the expression is one. Panics otherwise.
599 #[must_use]
600 fn to_complex(&self) -> ComplexExpr {
601 if let Self::Complex(x) = self {
602 x.clone()
603 } else {
604 panic!("self was not a complex");
605 }
606 }
607
608 /// Returns a circle if the expression is one. Panics otherwise.
609 #[must_use]
610 fn to_circle(&self) -> CircleExpr {
611 if let Self::Circle(x) = self {
612 x.clone()
613 } else {
614 panic!("self was not a circle");
615 }
616 }
617
618 /// Returns a scalar if the expression is one. Panics otherwise.
619 fn to_single(&self) -> RealExpr {
620 if let Self::This(x) = self {
621 x.clone()
622 } else {
623 panic!("self was not a single expression");
624 }
625 }
626}
627
628impl From<ComplexExpr> for ValueExpr {
629 fn from(value: ComplexExpr) -> Self {
630 Self::Complex(value)
631 }
632}
633
634impl From<LineExpr> for ValueExpr {
635 fn from(value: LineExpr) -> Self {
636 Self::Line(value)
637 }
638}
639
640impl From<CircleExpr> for ValueExpr {
641 fn from(value: CircleExpr) -> Self {
642 Self::Circle(value)
643 }
644}
645
646/// A line with an origin point and a normalized direction vector.
647#[derive(Debug, Clone)]
648struct LineExpr {
649 origin: ComplexExpr,
650 direction: ComplexExpr,
651}
652
653/// A circle with an origin and a radius.
654#[derive(Debug, Clone)]
655struct CircleExpr {
656 center: ComplexExpr,
657 radius: RealExpr,
658}
659
660// impl ComplexExpr {
661// /// Create a complex value from a real.
662// #[must_use]
663// fn real(real: CompiledExpr) -> Self {
664// Self {
665// real,
666// imaginary: Context::zero(),
667// }
668// }
669
670// /// Subtract complex values.
671// #[must_use]
672// fn sub(self, other: Self, context: &mut Context) -> Self {
673// Self {
674// real: context.sub(self.real, other.real),
675// imaginary: context.sub(self.imaginary, other.imaginary),
676// }
677// }
678
679// /// Add complex values.
680// #[must_use]
681// fn add(self, other: Self, context: &mut Context) -> Self {
682// Self {
683// real: context.add(self.real, other.real),
684// imaginary: context.add(self.imaginary, other.imaginary),
685// }
686// }
687
688// /// Add a real to a complex.
689// #[must_use]
690// fn add_real(self, other: CompiledExpr, context: &mut Context) -> Self {
691// Self {
692// real: context.add(self.real, other),
693// ..self
694// }
695// }
696
697// /// Multiply complex values.
698// #[must_use]
699// fn mul(self, other: Self, context: &mut Context) -> Self {
700// // self = a + bi
701// // other = c + di
702// // quotient = (ac - bd) + (ad + bc)i
703// let Self {
704// real: a,
705// imaginary: b,
706// } = self;
707// let Self {
708// real: c,
709// imaginary: d,
710// } = other;
711
712// let ac = context.mul(a, c);
713// let bd = context.mul(b, d);
714// let bc = context.mul(b, c);
715// let ad = context.mul(a, d);
716
717// let ac_sub_bd = context.sub(ac, bd);
718// let bc_plus_ad = context.add(bc, ad);
719
720// Self {
721// real: ac_sub_bd,
722// imaginary: bc_plus_ad,
723// }
724// }
725
726// /// Divide complex values.
727// #[must_use]
728// fn div(self, other: Self, context: &mut Context) -> Self {
729// // self = a + bi
730// // other = c + di
731// // quotient = ((ac + bd) + (bc - ad)i)/(c^2 + d^2)
732// let Self {
733// real: a,
734// imaginary: b,
735// } = self;
736// let Self {
737// real: c,
738// imaginary: d,
739// } = other;
740
741// let ac = context.mul(a, c);
742// let bd = context.mul(b, d);
743// let bc = context.mul(b, c);
744// let ad = context.mul(a, d);
745// let c2 = context.mul(c, c);
746// let d2 = context.mul(d, d);
747
748// let ac_plus_bd = context.add(ac, bd);
749// let bc_sub_ad = context.sub(bc, ad);
750// let c2_plus_d2 = context.add(c2, d2);
751
752// let real = context.div(ac_plus_bd, c2_plus_d2);
753// let imaginary = context.div(bc_sub_ad, c2_plus_d2);
754
755// Self { real, imaginary }
756// }
757
758// /// Multiply a complex by a real.
759// #[must_use]
760// fn mul_real(self, other: CompiledExpr, context: &mut Context) -> Self {
761// Self {
762// real: context.mul(self.real, other),
763// imaginary: context.mul(self.imaginary, other),
764// }
765// }
766
767// /// Divide a complex by a real.
768// #[must_use]
769// fn div_real(self, other: CompiledExpr, context: &mut Context) -> Self {
770// Self {
771// real: context.div(self.real, other),
772// imaginary: context.div(self.imaginary, other),
773// }
774// }
775
776// /// Get the magnitude of a complex as vector (distance from 0)
777// fn modulus(self, context: &mut Context) -> CompiledExpr {
778// // |a + bi| = (a^2 + b^2)^0.5
779// let a2 = context.mul(self.real, self.real);
780// let b2 = context.mul(self.imaginary, self.imaginary);
781// let a2_plus_b2 = context.add(a2, b2);
782// context.pow(a2_plus_b2, 0.5)
783// }
784
785// /// Negate the complex
786// #[must_use]
787// fn neg(self, context: &mut Context) -> Self {
788// Self {
789// real: context.neg(self.real),
790// imaginary: context.neg(self.imaginary),
791// }
792// }
793
794// /// A ternary operator. If `cond` is true, return `then`, otherwise return `else_`
795// #[must_use]
796// fn ternary(cond: Condition, then: Self, else_: Self, context: &mut Context) -> Self {
797// Self {
798// real: context.ternary(cond, then.real, else_.real),
799// imaginary: context.ternary(cond, then.imaginary, else_.imaginary),
800// }
801// }
802
803// /// Multiply the complex by `i`. A separate function as it's a simple operation.
804// #[must_use]
805// fn mul_i(self, context: &mut Context) -> Self {
806// Self {
807// real: context.neg(self.imaginary),
808// imaginary: self.real,
809// }
810// }
811
812// /// Raise the number to a power.
813// #[must_use]
814// fn pow(&self, exp: f64, context: &mut Context) -> Self {
815// let c = context.constant(exp);
816
817// let a2 = context.mul(self.real, self.real);
818// let b2 = context.mul(self.imaginary, self.imaginary);
819// let a2_plus_b2 = context.add(a2, b2);
820// let a2_plus_b2_to_exp_by_2 = context.pow(a2_plus_b2, exp / 2.0);
821
822// let arg = context.atan2(self.imaginary, self.real);
823// let c_arg = context.mul(c, arg);
824// let cos_c_arg = context.cos(c_arg);
825// let sin_c_arg = context.sin(c_arg);
826
827// Self {
828// real: context.mul(a2_plus_b2_to_exp_by_2, cos_c_arg),
829// imaginary: context.mul(a2_plus_b2_to_exp_by_2, sin_c_arg),
830// }
831// }
832// }
833
834/// Get a single complex from an iterator over floats.
835fn get_complex<I: Iterator<Item = f64>>(value: &mut I) -> Complex {
836 Complex::new(value.next().unwrap(), value.next().unwrap())
837}
838
839/// Create a figure based on its IR, figure's inputs and
840/// computed values for all figure's expressions.
841fn get_figure(figure: &crate::script::figure::Figure, values: &[f64]) -> Generated {
842 let mut value = values.iter().copied();
843
844 // println!("{:#?}, {values:?}", figure.variables);
845
846 let mut variables = Vec::new();
847 for expr in &figure.variables {
848 let v = match expr.ty {
849 ExprType::Point | ExprType::Number => ValueEnum::Complex(get_complex(&mut value)),
850 ExprType::Line => ValueEnum::Line(Line {
851 origin: get_complex(&mut value),
852 direction: get_complex(&mut value),
853 }),
854 ExprType::Circle => ValueEnum::Circle(Circle {
855 center: get_complex(&mut value),
856 radius: value.next().unwrap(),
857 }),
858 };
859 variables.push(Expr {
860 ty: expr.ty,
861 kind: expr.kind.clone(),
862 meta: v,
863 });
864 }
865
866 let mut entities = Vec::new();
867 for ent in &figure.entities {
868 let v = match ent {
869 EntityKind::PointOnCircle { .. }
870 | EntityKind::PointOnLine { .. }
871 | EntityKind::FreePoint => ValueEnum::Complex(get_complex(&mut value)),
872 EntityKind::DistanceUnit | EntityKind::FreeReal => {
873 ValueEnum::Complex(Complex::real(get_complex(&mut value).real))
874 }
875 EntityKind::Bind(_) => unreachable!(),
876 };
877 entities.push(Entity {
878 kind: ent.clone(),
879 meta: v,
880 });
881 }
882
883 Generated {
884 variables,
885 entities,
886 items: figure.items.clone(),
887 }
888}