1use std::cmp::Ordering;
31use std::collections::HashMap;
32
33use serde::Serialize;
34
35use super::{Channel, POWER_LIMIT, PRODUCT_LIMIT, Source};
36
37pub const TERM_LIMIT: usize = 64;
39
40const RAW_LIMIT: usize = u8::MAX as usize;
42
43pub fn saturate(x: f32) -> f32 {
45 if x.is_nan() { 0.0 } else { x.clamp(0.0, 1.0) }
46}
47
48pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
50 a + (b - a) * t
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
55#[serde(rename_all = "snake_case")]
56pub enum Term {
57 Constant(f32),
59 Source(u8),
61 Add([u8; 2]),
62 Subtract([u8; 2]),
64 Multiply([u8; 2]),
65 Min([u8; 2]),
66 Max([u8; 2]),
67 Saturate(u8),
69}
70
71impl Term {
72 pub fn operands(&self) -> &[u8] {
74 match self {
75 Term::Constant(_) | Term::Source(_) => &[],
76 Term::Add(o) | Term::Subtract(o) | Term::Multiply(o) | Term::Min(o) | Term::Max(o) => o,
77 Term::Saturate(o) => std::slice::from_ref(o),
78 }
79 }
80
81 fn commutative(&self) -> bool {
83 matches!(
84 self,
85 Term::Add(_) | Term::Multiply(_) | Term::Min(_) | Term::Max(_)
86 )
87 }
88
89 fn rank(&self) -> u8 {
91 match self {
92 Term::Constant(_) => 0,
93 Term::Source(_) => 1,
94 Term::Add(_) => 2,
95 Term::Subtract(_) => 3,
96 Term::Multiply(_) => 4,
97 Term::Min(_) => 5,
98 Term::Max(_) => 6,
99 Term::Saturate(_) => 7,
100 }
101 }
102
103 fn with_operands(&self, operands: &[u8]) -> Term {
105 let two = || [operands[0], operands[1]];
106 match self {
107 Term::Constant(_) | Term::Source(_) => *self,
108 Term::Add(_) => Term::Add(two()),
109 Term::Subtract(_) => Term::Subtract(two()),
110 Term::Multiply(_) => Term::Multiply(two()),
111 Term::Min(_) => Term::Min(two()),
112 Term::Max(_) => Term::Max(two()),
113 Term::Saturate(_) => Term::Saturate(operands[0]),
114 }
115 }
116
117 fn same(&self, other: &Term) -> bool {
119 let sorted = |t: &Term| {
120 let mut o = t.operands().to_vec();
121 if t.commutative() {
122 o.sort_unstable();
123 }
124 t.with_operands(&o)
125 };
126 match (self, other) {
127 (Term::Constant(a), Term::Constant(b)) => a.to_bits() == b.to_bits(),
128 _ => sorted(self) == sorted(other),
129 }
130 }
131}
132
133#[derive(Clone, Debug, PartialEq, Serialize)]
136pub struct Expression<S = Source> {
137 pub sources: Vec<S>,
139 pub terms: Vec<Term>,
141}
142
143impl<S: Clone + PartialEq + Serialize> Expression<S> {
144 pub fn evaluate(&self, values: &[f32]) -> f32 {
146 let mut v = [0.0f32; TERM_LIMIT];
147 for (i, term) in self.terms.iter().enumerate().take(TERM_LIMIT) {
148 let at = |k: u8| v[usize::from(k)];
149 v[i] = match *term {
150 Term::Constant(x) => x,
151 Term::Source(s) => values[usize::from(s)],
152 Term::Add([a, b]) => at(a) + at(b),
153 Term::Subtract([a, b]) => at(a) - at(b),
154 Term::Multiply([a, b]) => at(a) * at(b),
155 Term::Min([a, b]) => at(a).min(at(b)),
156 Term::Max([a, b]) => at(a).max(at(b)),
157 Term::Saturate(a) => saturate(at(a)),
158 };
159 }
160 self.terms
161 .len()
162 .checked_sub(1)
163 .and_then(|last| v.get(last))
164 .copied()
165 .unwrap_or(f32::NAN)
166 }
167
168 pub fn canonical(&self) -> Result<Expression<S>, String> {
171 let root = self
172 .terms
173 .len()
174 .checked_sub(1)
175 .ok_or("an expression without terms")?;
176 canonical(&self.sources, &self.terms, root)
177 }
178
179 pub fn check(&self) -> Result<(), String> {
182 let canonical = self.canonical()?;
183 if canonical != *self {
184 return Err(format!(
185 "expression is not canonical: {:?} is spelled {:?}",
186 self.terms, canonical.terms
187 ));
188 }
189 Ok(())
190 }
191}
192
193#[derive(Clone, Copy, Debug, PartialEq, Eq)]
195pub struct TermId(usize);
196
197#[derive(Clone, Debug)]
200pub struct ExpressionBuilder<S = Source> {
201 sources: Vec<S>,
202 terms: Vec<Term>,
203 overflow: bool,
205}
206
207impl<S> Default for ExpressionBuilder<S> {
208 fn default() -> Self {
209 ExpressionBuilder {
210 sources: Vec::new(),
211 terms: Vec::new(),
212 overflow: false,
213 }
214 }
215}
216
217impl<S: Clone + PartialEq + Serialize> ExpressionBuilder<S> {
218 pub fn new() -> Self {
219 Self::default()
220 }
221
222 fn push(&mut self, t: Term) -> TermId {
223 if self.terms.len() >= RAW_LIMIT {
224 self.overflow = true;
225 return TermId(0);
226 }
227 self.terms.push(t);
228 TermId(self.terms.len() - 1)
229 }
230
231 fn index(&mut self, v: TermId) -> u8 {
232 u8::try_from(v.0).unwrap_or_else(|_| {
233 self.overflow = true;
234 0
235 })
236 }
237
238 pub fn source(&mut self, s: S) -> TermId {
239 self.sources.push(s);
240 let i = self.sources.len() - 1;
241 let i = u8::try_from(i).unwrap_or_else(|_| {
242 self.overflow = true;
243 0
244 });
245 self.push(Term::Source(i))
246 }
247
248 pub fn constant(&mut self, x: f32) -> TermId {
249 self.push(Term::Constant(x))
250 }
251
252 fn binary(&mut self, a: TermId, b: TermId, make: fn([u8; 2]) -> Term) -> TermId {
253 let o = [self.index(a), self.index(b)];
254 self.push(make(o))
255 }
256
257 pub fn add(&mut self, a: TermId, b: TermId) -> TermId {
258 self.binary(a, b, Term::Add)
259 }
260
261 pub fn subtract(&mut self, a: TermId, b: TermId) -> TermId {
263 self.binary(a, b, Term::Subtract)
264 }
265
266 pub fn multiply(&mut self, a: TermId, b: TermId) -> TermId {
267 self.binary(a, b, Term::Multiply)
268 }
269
270 pub fn min(&mut self, a: TermId, b: TermId) -> TermId {
271 self.binary(a, b, Term::Min)
272 }
273
274 pub fn max(&mut self, a: TermId, b: TermId) -> TermId {
275 self.binary(a, b, Term::Max)
276 }
277
278 pub fn saturate(&mut self, a: TermId) -> TermId {
279 let o = self.index(a);
280 self.push(Term::Saturate(o))
281 }
282
283 pub fn lerp(&mut self, a: TermId, b: TermId, t: TermId) -> TermId {
285 let d = self.subtract(b, a);
286 let s = self.multiply(d, t);
287 self.add(a, s)
288 }
289
290 pub fn power(&mut self, v: TermId, exponent: u8) -> TermId {
292 if exponent == 0 {
293 return self.constant(1.0);
294 }
295 if exponent.is_power_of_two() {
296 (0..exponent.trailing_zeros()).fold(v, |x, _| self.multiply(x, x))
297 } else {
298 (1..exponent).fold(v, |x, _| self.multiply(x, v))
299 }
300 }
301
302 pub fn expression(&self, root: TermId) -> Result<Expression<S>, String> {
304 if self.overflow {
305 return Err(format!(
306 "an expression spelled in more than {RAW_LIMIT} terms or sources"
307 ));
308 }
309 if root.0 >= self.terms.len() {
310 return Err(format!("term {} is not in the expression", root.0));
311 }
312 canonical(&self.sources, &self.terms, root.0)
313 }
314}
315
316impl ExpressionBuilder {
317 pub fn channel(&self, root: TermId) -> Result<Channel, String> {
319 self.expression(root).map(Channel::from_expression_canonical)
320 }
321}
322
323fn well_formed<S>(sources: &[S], terms: &[Term], root: usize) -> Result<(), String> {
325 if terms.len() > RAW_LIMIT || sources.len() > RAW_LIMIT {
326 return Err(format!(
327 "an expression spelled in more than {RAW_LIMIT} terms or sources"
328 ));
329 }
330 for (i, t) in terms.iter().enumerate().take(root + 1) {
331 if let Some(&o) = t.operands().iter().find(|&&o| usize::from(o) >= i) {
332 return Err(format!("term {i} reads term {o}, which is not before it"));
333 }
334 match *t {
335 Term::Source(s) if usize::from(s) >= sources.len() => {
336 return Err(format!("term {i} reads source {s} of {}", sources.len()));
337 }
338 Term::Constant(x) if !x.is_finite() => {
339 return Err(format!("term {i}: constant {x} is not finite"));
340 }
341 _ => {}
342 }
343 }
344 Ok(())
345}
346
347fn canonical<S: Clone + PartialEq + Serialize>(
349 sources: &[S],
350 terms: &[Term],
351 root: usize,
352) -> Result<Expression<S>, String> {
353 well_formed(sources, terms, root)?;
354 let mut needed = vec![false; root + 1];
355 needed[root] = true;
356 for i in (0..=root).rev() {
357 if needed[i] {
358 for &o in terms[i].operands() {
359 needed[usize::from(o)] = true;
360 }
361 }
362 }
363 let mut distinct: Vec<&S> = Vec::new();
365 let mut classes: Vec<Term> = Vec::new();
366 let mut class_of = vec![0u8; root + 1];
367 for i in (0..=root).filter(|&i| needed[i]) {
368 let operands: Vec<u8> = terms[i]
369 .operands()
370 .iter()
371 .map(|&o| class_of[usize::from(o)])
372 .collect();
373 let term = match terms[i] {
374 Term::Source(s) => {
375 let s = &sources[usize::from(s)];
376 let d = distinct.iter().position(|x| *x == s).unwrap_or_else(|| {
377 distinct.push(s);
378 distinct.len() - 1
379 });
380 Term::Source(d as u8)
381 }
382 Term::Constant(x) => Term::Constant(if x == 0.0 { 0.0 } else { x }),
384 t => t.with_operands(&operands),
385 };
386 let class = classes.iter().position(|c| c.same(&term)).unwrap_or_else(|| {
387 classes.push(term);
388 classes.len() - 1
389 });
390 class_of[i] = class as u8;
391 }
392 let keys = distinct
393 .iter()
394 .map(|s| serde_json::to_string(s).map_err(|e| format!("a source without a key: {e}")))
395 .collect::<Result<Vec<String>, String>>()?;
396 let mut order = Order {
397 classes: &classes,
398 keys: &keys,
399 memo: HashMap::new(),
400 };
401 let mut emit = Emit {
402 index: vec![None; classes.len()],
403 source_index: vec![None; distinct.len()],
404 sources: Vec::new(),
405 terms: Vec::new(),
406 };
407 emit.class(&mut order, &distinct, usize::from(class_of[root]));
408 if emit.terms.len() > TERM_LIMIT {
409 return Err(format!(
410 "an expression of {} terms, past {TERM_LIMIT}",
411 emit.terms.len()
412 ));
413 }
414 Ok(Expression {
415 sources: emit.sources,
416 terms: emit.terms,
417 })
418}
419
420struct Order<'a> {
423 classes: &'a [Term],
424 keys: &'a [String],
425 memo: HashMap<(usize, usize), Ordering>,
426}
427
428impl Order<'_> {
429 fn operands(&mut self, c: usize) -> Vec<usize> {
430 let t = self.classes[c];
431 let mut o: Vec<usize> = t.operands().iter().map(|&o| usize::from(o)).collect();
432 if t.commutative() && self.cmp(o[1], o[0]) == Ordering::Less {
433 o.swap(0, 1);
434 }
435 o
436 }
437
438 fn cmp(&mut self, a: usize, b: usize) -> Ordering {
439 if a == b {
440 return Ordering::Equal;
441 }
442 if let Some(&o) = self.memo.get(&(a, b)) {
443 return o;
444 }
445 let (x, y) = (self.classes[a], self.classes[b]);
446 let o = match (x, y) {
447 _ if x.rank() != y.rank() => x.rank().cmp(&y.rank()),
448 (Term::Constant(p), Term::Constant(q)) => p.total_cmp(&q),
449 (Term::Source(p), Term::Source(q)) => self.keys[usize::from(p)].cmp(&self.keys[usize::from(q)]),
450 _ => {
451 let (p, q) = (self.operands(a), self.operands(b));
452 p.iter()
453 .zip(&q)
454 .map(|(&i, &j)| self.cmp(i, j))
455 .find(|o| o.is_ne())
456 .unwrap_or(Ordering::Equal)
457 }
458 };
459 self.memo.insert((a, b), o);
460 o
461 }
462}
463
464struct Emit<S> {
466 index: Vec<Option<u8>>,
467 source_index: Vec<Option<u8>>,
468 sources: Vec<S>,
469 terms: Vec<Term>,
470}
471
472impl<S: Clone> Emit<S> {
473 fn class(&mut self, order: &mut Order, distinct: &[&S], c: usize) -> u8 {
474 if let Some(i) = self.index[c] {
475 return i;
476 }
477 let operands: Vec<u8> = order
478 .operands(c)
479 .into_iter()
480 .map(|o| self.class(order, distinct, o))
481 .collect();
482 let term = match order.classes[c] {
483 Term::Source(s) => {
484 let s = usize::from(s);
485 let i = *self.source_index[s].get_or_insert_with(|| {
486 self.sources.push(distinct[s].clone());
487 (self.sources.len() - 1) as u8
488 });
489 Term::Source(i)
490 }
491 t => t.with_operands(&operands),
492 };
493 self.terms.push(term);
494 let i = (self.terms.len() - 1) as u8;
495 self.index[c] = Some(i);
496 i
497 }
498}
499
500impl Channel {
501 pub fn expression(&self) -> Result<Expression, String> {
503 self.check()?;
504 let mut b = ExpressionBuilder::new();
505 let root = match self {
506 Channel::Source(s) => b.source(s.clone()),
507 Channel::Lerp { a, b: to, t } => {
508 let (a, to, t) = (b.source(a.clone()), b.source(to.clone()), b.source(t.clone()));
509 b.lerp(a, to, t)
510 }
511 Channel::Threshold { v, m, k } => {
512 let (v, m) = (b.source(v.clone()), b.source(m.clone()));
514 let [k0, k1, k2, k3] = k.map(|x| b.constant(x));
515 let k1v = b.multiply(k1, v);
516 let x = b.add(k0, k1v);
517 let k2m = b.multiply(k2, m);
518 let x = b.add(x, k2m);
519 let k3v = b.multiply(k3, v);
520 let k3vm = b.multiply(k3v, m);
521 let x = b.add(x, k3vm);
522 b.saturate(x)
523 }
524 Channel::Product { sources } => {
525 let mut values = sources
526 .iter()
527 .map(|s| b.source(s.clone()))
528 .collect::<Vec<_>>()
529 .into_iter();
530 let first = values.next().ok_or("a product of no sources")?;
531 values.fold(first, |p, v| b.multiply(p, v))
532 }
533 Channel::Power { v, exponent } => {
534 let v = b.source(v.clone());
535 b.power(v, *exponent)
536 }
537 Channel::Expression(e) => return Ok(e.clone()),
538 };
539 b.expression(root)
540 }
541
542 pub fn from_expression(e: &Expression) -> Result<Channel, String> {
544 e.canonical().map(Self::from_expression_canonical)
545 }
546
547 fn from_expression_canonical(e: Expression) -> Channel {
549 named(&e).unwrap_or(Channel::Expression(e))
550 }
551}
552
553fn named(e: &Expression) -> Option<Channel> {
556 let constants: Vec<f32> = e
557 .terms
558 .iter()
559 .filter_map(|t| match t {
560 Term::Constant(x) => Some(*x),
561 _ => None,
562 })
563 .collect();
564 let s = &e.sources;
565 let mut candidates: Vec<Channel> = Vec::new();
566 match e.terms.last()? {
567 Term::Source(_) => candidates.push(Channel::Source(s.first()?.clone())),
568 Term::Multiply(_) if constants.is_empty() => {
569 if s.len() == 1 {
570 candidates.extend((2..=POWER_LIMIT).map(|exponent| Channel::Power {
571 v: s[0].clone(),
572 exponent,
573 }));
574 }
575 if s.len() <= PRODUCT_LIMIT {
576 for n in 2..=PRODUCT_LIMIT {
577 candidates.extend(sequences(s, n).map(|sources| Channel::Product { sources }));
578 }
579 }
580 }
581 Term::Add(_) if constants.is_empty() && s.len() <= 3 => {
582 candidates.extend(sequences(s, 3).map(|mut abt| {
583 let (t, b, a) = (abt.remove(2), abt.remove(1), abt.remove(0));
584 Channel::Lerp { a, b, t }
585 }));
586 }
587 Term::Saturate(_) if s.len() <= 2 && constants.len() <= 4 && e.terms.len() <= 14 => {
588 let ks = (0..constants.len().pow(4)).map(|mut n| {
589 std::array::from_fn(|_| {
590 let k = constants[n % constants.len()];
591 n /= constants.len();
592 k
593 })
594 });
595 let ks: Vec<[f32; 4]> = ks.collect();
596 for vm in sequences(s, 2) {
597 candidates.extend(ks.iter().map(|&k| Channel::Threshold {
598 v: vm[0].clone(),
599 m: vm[1].clone(),
600 k,
601 }));
602 }
603 }
604 _ => {}
605 }
606 candidates
607 .into_iter()
608 .find(|c| c.expression().is_ok_and(|x| x == *e))
609}
610
611fn sequences(sources: &[Source], n: usize) -> impl Iterator<Item = Vec<Source>> + '_ {
613 let k = sources.len();
614 let count = if k == 0 { 0 } else { k.pow(n as u32) };
615 (0..count).filter_map(move |mut x| {
616 let mut picks = vec![0; n];
617 for p in picks.iter_mut().rev() {
618 *p = x % k;
619 x /= k;
620 }
621 (0..k)
622 .all(|s| picks.contains(&s))
623 .then(|| picks.iter().map(|&p| sources[p].clone()).collect())
624 })
625}