Skip to main content

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 * &quotient;
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}