1use crate::complex::Complex;
10use crate::continuous::Family;
11use crate::dist::Dist;
12use rustc_hash::FxHasher;
13use std::cmp::Ordering;
14use std::collections::BTreeMap;
15use std::fmt;
16use std::hash::{Hash, Hasher};
17use std::ops::{Deref, DerefMut};
18use std::sync::Arc;
19use std::sync::atomic::{AtomicU64, Ordering as Atomic};
20
21#[derive(Clone)]
22pub enum Value {
23 Dead,
25 Unit,
26 Bool(bool),
28 Int(probl_number::Integer),
29 Float(f64),
30 Complex(Complex),
31 Prob(f64),
33 Str(Arc<str>),
34 List(Arc<Hashed<Vec<Value>>>),
35 Map(Arc<Hashed<BTreeMap<Value, Value>>>),
36 Bag(Arc<Hashed<Multiset>>),
38 Range(probl_number::Integer, probl_number::Integer),
40 Record(Arc<Hashed<Record>>),
41 Enum(Arc<EnumValue>),
42 Dist(Arc<Dist>),
43 Continuous(Arc<Family>),
45 Closure(Arc<Closure>),
46 Builtin(probl_sema::Builtin),
47 Date(i32),
49 Delayed(Arc<Delayed>),
53 Analytic(Arc<crate::analytic::Analytic>),
55 Event(Arc<crate::analytic::Event>),
57 Counts(Arc<crate::dist::Counts>),
62 Joint(Arc<crate::dist::Dist>),
66}
67
68#[derive(Clone, Copy, Debug, PartialEq)]
71pub struct Delayed {
72 pub family: Family,
73 pub variable: u32,
76}
77
78pub struct Hashed<T> {
84 hash: AtomicU64,
86 value: T,
87}
88
89impl<T> Hashed<T> {
90 pub fn new(value: T) -> Hashed<T> {
91 Hashed {
92 hash: AtomicU64::new(0),
93 value,
94 }
95 }
96
97 pub(crate) fn known_hash(&self) -> u64 {
98 self.hash.load(Atomic::Relaxed)
99 }
100}
101
102impl<T: Hash> Hashed<T> {
103 pub fn hash_code(&self) -> u64 {
105 let known = self.known_hash();
106 if known != 0 {
107 return known;
108 }
109 let mut hasher = FxHasher::default();
110 self.value.hash(&mut hasher);
111 let h = hasher.finish().max(1);
112 self.hash.store(h, Atomic::Relaxed);
113 h
114 }
115}
116
117impl<T> Deref for Hashed<T> {
118 type Target = T;
119
120 fn deref(&self) -> &T {
121 &self.value
122 }
123}
124
125impl<T> DerefMut for Hashed<T> {
126 fn deref_mut(&mut self) -> &mut T {
127 *self.hash.get_mut() = 0;
128 &mut self.value
129 }
130}
131
132impl<T: Clone> Clone for Hashed<T> {
133 fn clone(&self) -> Hashed<T> {
134 Hashed {
135 hash: AtomicU64::new(self.known_hash()),
136 value: self.value.clone(),
137 }
138 }
139}
140
141impl<T: PartialEq> PartialEq for Hashed<T> {
142 fn eq(&self, other: &Hashed<T>) -> bool {
143 let (a, b) = (self.known_hash(), other.known_hash());
144 (a == 0 || b == 0 || a == b) && self.value == other.value
145 }
146}
147
148impl<T: Eq> Eq for Hashed<T> {}
149
150impl<T: Hash> Hash for Hashed<T> {
151 fn hash<H: Hasher>(&self, state: &mut H) {
152 state.write_u64(self.hash_code());
153 }
154}
155
156impl<T: Ord> PartialOrd for Hashed<T> {
157 fn partial_cmp(&self, other: &Hashed<T>) -> Option<Ordering> {
158 Some(self.cmp(other))
159 }
160}
161
162impl<T: Ord> Ord for Hashed<T> {
163 fn cmp(&self, other: &Hashed<T>) -> Ordering {
164 self.value.cmp(&other.value)
165 }
166}
167
168impl<T: fmt::Debug> fmt::Debug for Hashed<T> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 self.value.fmt(f)
171 }
172}
173
174#[derive(Clone, Debug, Default)]
179pub struct Multiset {
180 entries: Vec<(Value, u64)>,
181 sum: u64,
184}
185
186fn entry_hash(v: &Value, n: u64) -> u64 {
189 let mut hasher = FxHasher::default();
190 v.hash(&mut hasher);
191 n.hash(&mut hasher);
192 crate::continuous::mix(hasher.finish())
193}
194
195impl Multiset {
196 pub fn new(counts: BTreeMap<Value, u64>) -> Multiset {
198 let entries: Vec<(Value, u64)> = counts.into_iter().filter(|(_, n)| *n > 0).collect();
199 let sum = entries
200 .iter()
201 .fold(0u64, |sum, (v, n)| sum.wrapping_add(entry_hash(v, *n)));
202 Multiset { entries, sum }
203 }
204
205 pub fn iter(&self) -> impl Iterator<Item = (&Value, &u64)> + Clone {
206 self.entries.iter().map(|(v, n)| (v, n))
207 }
208
209 pub fn keys(&self) -> impl Iterator<Item = &Value> + Clone {
210 self.entries.iter().map(|(v, _)| v)
211 }
212
213 pub fn values(&self) -> impl Iterator<Item = &u64> + Clone {
214 self.entries.iter().map(|(_, n)| n)
215 }
216
217 pub fn get(&self, v: &Value) -> Option<&u64> {
219 let i = self.entries.binary_search_by(|(k, _)| k.cmp(v)).ok()?;
220 Some(&self.entries[i].1)
221 }
222
223 pub fn without_nth(&self, i: usize) -> Multiset {
225 let mut entries = self.entries.clone();
226 let (v, n) = (&self.entries[i].0, self.entries[i].1);
227 let mut sum = self.sum.wrapping_sub(entry_hash(v, n));
228 if n > 1 {
229 entries[i].1 = n - 1;
230 sum = sum.wrapping_add(entry_hash(v, n - 1));
231 } else {
232 entries.remove(i);
233 }
234 Multiset { entries, sum }
235 }
236
237 pub fn without(&self, v: &Value) -> Option<Multiset> {
239 let i = self.entries.binary_search_by(|(k, _)| k.cmp(v)).ok()?;
240 Some(self.without_nth(i))
241 }
242}
243
244impl PartialEq for Multiset {
245 fn eq(&self, other: &Multiset) -> bool {
246 self.sum == other.sum && self.entries == other.entries
247 }
248}
249
250impl Eq for Multiset {}
251
252impl Hash for Multiset {
253 fn hash<H: Hasher>(&self, state: &mut H) {
254 state.write_u64(self.sum);
255 }
256}
257
258impl PartialOrd for Multiset {
259 fn partial_cmp(&self, other: &Multiset) -> Option<Ordering> {
260 Some(self.cmp(other))
261 }
262}
263
264impl Ord for Multiset {
265 fn cmp(&self, other: &Multiset) -> Ordering {
266 self.entries.cmp(&other.entries)
267 }
268}
269
270#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
271pub struct Record {
272 pub ty: Option<Arc<str>>,
273 pub fields: Vec<(Arc<str>, Value)>,
275}
276
277impl Record {
278 pub fn get(&self, name: &str) -> Option<&Value> {
279 self.fields.iter().find(|(n, _)| &**n == name).map(|(_, v)| v)
280 }
281
282 pub fn get_mut(&mut self, name: &str) -> Option<&mut Value> {
283 self.fields.iter_mut().find(|(n, _)| &**n == name).map(|(_, v)| v)
284 }
285}
286
287#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
288pub struct EnumValue {
289 pub ty: u32,
290 pub variant: u32,
291 pub name: Arc<str>,
292}
293
294#[derive(Clone, Debug)]
295pub struct Closure {
296 pub func: u32,
297 pub captured: Vec<Value>,
298 pub named: bool,
302}
303
304impl Closure {
305 fn identity(&self) -> (u32, &[Value]) {
306 (self.func, if self.named { &[] } else { &self.captured })
307 }
308}
309
310impl PartialEq for Closure {
311 fn eq(&self, other: &Closure) -> bool {
312 self.identity() == other.identity()
313 }
314}
315
316impl Eq for Closure {}
317
318impl Hash for Closure {
319 fn hash<H: Hasher>(&self, state: &mut H) {
320 self.identity().hash(state)
321 }
322}
323
324impl PartialOrd for Closure {
325 fn partial_cmp(&self, other: &Closure) -> Option<Ordering> {
326 Some(self.cmp(other))
327 }
328}
329
330impl Ord for Closure {
331 fn cmp(&self, other: &Closure) -> Ordering {
332 self.identity().cmp(&other.identity())
333 }
334}
335
336impl Value {
337 pub fn str(s: &str) -> Value {
338 Value::Str(Arc::from(s))
339 }
340
341 pub fn list(items: Vec<Value>) -> Value {
342 Value::List(Arc::new(Hashed::new(items)))
343 }
344
345 pub fn map(entries: BTreeMap<Value, Value>) -> Value {
346 Value::Map(Arc::new(Hashed::new(entries)))
347 }
348
349 pub fn bag(counts: BTreeMap<Value, u64>) -> Value {
350 Value::multiset(Multiset::new(counts))
351 }
352
353 pub fn multiset(contents: Multiset) -> Value {
354 Value::Bag(Arc::new(Hashed::new(contents)))
355 }
356
357 pub fn record(record: Record) -> Value {
358 Value::Record(Arc::new(Hashed::new(record)))
359 }
360
361 pub fn unshared(&self) -> Value {
365 self.unshared_with(&mut rustc_hash::FxHashMap::default())
366 }
367
368 fn unshared_with(&self, names: &mut rustc_hash::FxHashMap<String, Arc<str>>) -> Value {
371 fn name(names: &mut rustc_hash::FxHashMap<String, Arc<str>>, n: &str) -> Arc<str> {
372 names.entry(n.to_string()).or_insert_with(|| Arc::from(n)).clone()
373 }
374 match self {
375 Value::Str(s) => Value::str(s),
376 Value::Enum(e) => Value::Enum(Arc::new(EnumValue {
377 name: name(names, &e.name),
378 ..(**e).clone()
379 })),
380 Value::Record(r) => {
381 let ty = r.ty.as_deref().map(|t| name(names, t));
382 let mut fields = Vec::with_capacity(r.fields.len());
383 for (n, v) in &r.fields {
384 fields.push((name(names, n), v.unshared_with(names)));
385 }
386 Value::record(Record { ty, fields })
387 }
388 Value::List(items) => Value::list(items.iter().map(|x| x.unshared_with(names)).collect()),
389 Value::Map(m) => Value::map(
390 m.iter()
391 .map(|(k, v)| (k.unshared_with(names), v.unshared_with(names)))
392 .collect(),
393 ),
394 Value::Bag(b) => Value::multiset(Multiset {
395 entries: b.entries.iter().map(|(v, n)| (v.unshared_with(names), *n)).collect(),
396 sum: b.sum,
397 }),
398 other => other.clone(),
399 }
400 }
401
402 pub fn kind(&self) -> String {
404 match self {
405 Value::Dead => "nothing".into(),
406 Value::Unit => "()".into(),
407 Value::Bool(_) => "bool".into(),
408 Value::Int(_) => "int".into(),
409 Value::Float(_) => "float".into(),
410 Value::Complex(_) => "complex".into(),
411 Value::Prob(_) => "prob".into(),
412 Value::Str(_) => "str".into(),
413 Value::List(_) => "list".into(),
414 Value::Map(_) => "map".into(),
415 Value::Bag(_) => "bag".into(),
416 Value::Range(..) => "range".into(),
417 Value::Record(r) => match &r.ty {
418 Some(t) => t.to_string(),
419 None => "record".into(),
420 },
421 Value::Enum(_) => "enum".into(),
422 Value::Dist(d) if d.outcomes.iter().any(|(v, _)| matches!(v, Value::Continuous(_))) => {
423 "mixture of distributions".into()
424 }
425 Value::Dist(d) => match d.outcomes.first() {
426 Some((v, _)) => format!("distribution over {}", plural_kind(&v.kind())),
427 None => "distribution".into(),
428 },
429 Value::Continuous(f) => format!("{} distribution", f.name()),
430 Value::Closure(_) | Value::Builtin(_) => "function".into(),
431 Value::Date(_) => "date".into(),
432 Value::Delayed(_) => "value not drawn yet".into(),
433 Value::Analytic(a) if a.int => "int".into(),
434 Value::Analytic(_) => "float".into(),
435 Value::Event(_) => "bool".into(),
436 Value::Counts(_) => "distribution over ints".into(),
437 Value::Joint(d) => match d.outcomes.first() {
438 Some((v, _)) => format!("distribution over {}", plural_kind(&v.kind())),
439 None => "distribution".into(),
440 },
441 }
442 }
443
444 pub fn is_dist(&self) -> bool {
446 matches!(self, Value::Dist(_))
447 }
448
449 pub fn is_uncertain(&self) -> bool {
451 matches!(
452 self,
453 Value::Dist(_) | Value::Continuous(_) | Value::Counts(_) | Value::Joint(_)
454 )
455 }
456
457 pub fn as_f64(&self) -> Option<f64> {
459 match self {
460 Value::Int(i) => i.to_f64(),
461 Value::Float(f) | Value::Prob(f) => Some(*f),
462 _ => None,
463 }
464 }
465
466 pub fn as_complex(&self) -> Option<Complex> {
469 match self {
470 Value::Complex(z) => Some(*z),
471 _ => self.as_f64().and_then(|x| Complex::new(x, 0.0).ok()),
472 }
473 }
474
475 fn rank(&self) -> u8 {
477 match self {
478 Value::Dead => 0,
479 Value::Unit => 1,
480 Value::Bool(_) => 2,
481 Value::Int(_) | Value::Float(_) | Value::Prob(_) => 3,
482 Value::Str(_) => 4,
483 Value::Date(_) => 5,
484 Value::Enum(_) => 6,
485 Value::List(_) => 7,
486 Value::Range(..) => 8,
487 Value::Map(_) => 9,
488 Value::Bag(_) => 10,
489 Value::Record(_) => 11,
490 Value::Dist(_) => 12,
491 Value::Closure(_) => 13,
492 Value::Builtin(_) => 19,
493 Value::Continuous(_) => 14,
494 Value::Delayed(_) => 15,
495 Value::Complex(_) => 16,
496 Value::Analytic(_) => 17,
497 Value::Event(_) => 18,
498 Value::Counts(_) => 20,
499 Value::Joint(_) => 21,
500 }
501 }
502
503 fn number_rank(&self) -> u8 {
504 match self {
505 Value::Int(_) => 0,
506 Value::Float(_) => 1,
507 _ => 2,
508 }
509 }
510}
511
512fn plural_kind(kind: &str) -> String {
513 match kind {
514 "str" => "strings".into(),
515 "prob" => "probabilities".into(),
516 "list" => "lists".into(),
517 k => format!("{k}s"),
518 }
519}
520
521pub(crate) fn family_key(f: &Family) -> (&'static str, Vec<u64>) {
523 (f.name(), f.params().into_iter().map(float_key).collect())
524}
525
526pub(crate) fn float_key(f: f64) -> u64 {
528 if f == 0.0 {
529 0
530 } else if f.is_nan() {
531 f64::NAN.to_bits()
532 } else {
533 f.to_bits()
534 }
535}
536
537impl PartialEq for Value {
538 #[inline]
541 fn eq(&self, other: &Value) -> bool {
542 match (self, other) {
543 (Value::Int(a), Value::Int(b)) => a == b,
544 (Value::Bool(a), Value::Bool(b)) => a == b,
545 (Value::Dead, Value::Dead) => true,
546 _ => eq_other(self, other),
547 }
548 }
549}
550
551#[inline(never)]
552fn eq_other(x: &Value, y: &Value) -> bool {
553 match (x, y) {
554 (Value::Unit, Value::Unit) => true,
555 (Value::Float(a), Value::Float(b)) | (Value::Prob(a), Value::Prob(b)) => float_key(*a) == float_key(*b),
556 (Value::Complex(a), Value::Complex(b)) => a == b,
557 (Value::Str(a), Value::Str(b)) => a == b,
558 (Value::List(a), Value::List(b)) => Arc::ptr_eq(a, b) || a == b,
559 (Value::Map(a), Value::Map(b)) => Arc::ptr_eq(a, b) || a == b,
560 (Value::Bag(a), Value::Bag(b)) => Arc::ptr_eq(a, b) || a == b,
561 (Value::Range(a, b), Value::Range(c, d)) => a == c && b == d,
562 (Value::Record(a), Value::Record(b)) => Arc::ptr_eq(a, b) || a == b,
563 (Value::Enum(a), Value::Enum(b)) => a.ty == b.ty && a.variant == b.variant,
564 (Value::Dist(a), Value::Dist(b)) => Arc::ptr_eq(a, b) || a == b,
565 (Value::Closure(a), Value::Closure(b)) => Arc::ptr_eq(a, b) || a == b,
566 (Value::Builtin(a), Value::Builtin(b)) => a == b,
567 (Value::Date(a), Value::Date(b)) => a == b,
568 (Value::Continuous(a), Value::Continuous(b)) => family_key(a) == family_key(b),
569 (Value::Analytic(a), Value::Analytic(b)) => a.key() == b.key(),
570 (Value::Event(a), Value::Event(b)) => a.key() == b.key(),
571 (Value::Counts(a), Value::Counts(b)) => a.key() == b.key(),
572 (Value::Joint(a), Value::Joint(b)) => Arc::ptr_eq(a, b) || a == b,
573 (Value::Delayed(a), Value::Delayed(b)) => {
574 a.variable == b.variable && family_key(&a.family) == family_key(&b.family)
575 }
576 _ => false,
577 }
578}
579
580impl Eq for Value {}
581
582pub fn eq_counted(a: &Value, b: &Value, budget: &mut crate::dist::Budget) -> crate::error::OpResult<bool> {
586 fn differ<T>(x: &Hashed<T>, y: &Hashed<T>) -> bool {
588 let (p, q) = (x.known_hash(), y.known_hash());
589 p != 0 && q != 0 && p != q
590 }
591 fn same(p: &Value, q: &Value, budget: &mut crate::dist::Budget) -> crate::error::OpResult<bool> {
592 match p {
593 Value::List(_) | Value::Map(_) | Value::Bag(_) | Value::Record(_) => eq_counted(p, q, budget),
594 _ => Ok(p == q),
595 }
596 }
597 let mut compared = 0;
600 let mut equal = true;
601 match (a, b) {
602 (Value::List(x), Value::List(y)) => {
603 if Arc::ptr_eq(x, y) {
604 return Ok(true);
605 }
606 if x.len() != y.len() || differ(x, y) {
607 return Ok(false);
608 }
609 for (p, q) in x.iter().zip(y.iter()) {
610 compared += 1;
611 if !same(p, q, budget)? {
612 equal = false;
613 break;
614 }
615 }
616 }
617 (Value::Map(x), Value::Map(y)) => {
618 if Arc::ptr_eq(x, y) {
619 return Ok(true);
620 }
621 if x.len() != y.len() || differ(x, y) {
622 return Ok(false);
623 }
624 for ((k, v), (l, u)) in x.iter().zip(y.iter()) {
625 compared += 1;
626 if !same(k, l, budget)? || !same(v, u, budget)? {
627 equal = false;
628 break;
629 }
630 }
631 }
632 (Value::Bag(x), Value::Bag(y)) => {
633 if Arc::ptr_eq(x, y) {
634 return Ok(true);
635 }
636 if x.sum != y.sum || x.entries.len() != y.entries.len() || differ(x, y) {
637 return Ok(false);
638 }
639 for ((v, n), (u, m)) in x.entries.iter().zip(y.entries.iter()) {
640 compared += 1;
641 if n != m || !same(v, u, budget)? {
642 equal = false;
643 break;
644 }
645 }
646 }
647 (Value::Record(x), Value::Record(y)) => {
648 if Arc::ptr_eq(x, y) {
649 return Ok(true);
650 }
651 if x.ty != y.ty || x.fields.len() != y.fields.len() || differ(x, y) {
652 return Ok(false);
653 }
654 for ((n, v), (m, u)) in x.fields.iter().zip(y.fields.iter()) {
655 compared += 1;
656 if n != m || !same(v, u, budget)? {
657 equal = false;
658 break;
659 }
660 }
661 }
662 _ => return Ok(a == b),
663 }
664 budget.work(compared)?;
665 Ok(equal)
666}
667
668impl Hash for Value {
669 #[inline]
671 fn hash<H: Hasher>(&self, state: &mut H) {
672 std::mem::discriminant(self).hash(state);
673 match self {
674 Value::Dead | Value::Unit => {}
675 Value::Bool(b) => b.hash(state),
676 Value::Int(i) => i.hash(state),
677 other => hash_other(other, state),
678 }
679 }
680}
681
682#[inline(never)]
683fn hash_other<H: Hasher>(value: &Value, state: &mut H) {
684 match value {
685 Value::Dead | Value::Unit | Value::Bool(_) | Value::Int(_) => {}
686 Value::Float(f) | Value::Prob(f) => float_key(*f).hash(state),
687 Value::Complex(z) => (float_key(z.re()), float_key(z.im())).hash(state),
688 Value::Str(s) => s.hash(state),
689 Value::List(items) => items.hash(state),
690 Value::Map(m) => m.hash(state),
691 Value::Bag(b) => b.hash(state),
692 Value::Range(a, b) => (a, b).hash(state),
693 Value::Record(r) => r.hash(state),
694 Value::Enum(e) => (e.ty, e.variant).hash(state),
695 Value::Dist(d) => d.hash(state),
696 Value::Closure(c) => c.hash(state),
697 Value::Builtin(b) => b.hash(state),
698 Value::Date(d) => d.hash(state),
699 Value::Continuous(f) => family_key(f).hash(state),
700 Value::Analytic(a) => a.key().hash(state),
701 Value::Event(a) => a.key().hash(state),
702 Value::Delayed(d) => (d.variable, family_key(&d.family)).hash(state),
703 Value::Counts(c) => c.key().hash(state),
704 Value::Joint(d) => d.hash(state),
705 }
706}
707
708impl Ord for Value {
709 fn cmp(&self, other: &Value) -> Ordering {
710 let (ra, rb) = (self.rank(), other.rank());
711 if ra != rb {
712 return ra.cmp(&rb);
713 }
714 match (self, other) {
715 (Value::Int(a), Value::Int(b)) => a.cmp(b),
716 (Value::Int(a), Value::Float(b) | Value::Prob(b)) => a
717 .cmp_f64(*b)
718 .unwrap_or(Ordering::Less)
719 .then_with(|| self.number_rank().cmp(&other.number_rank())),
720 (Value::Float(a) | Value::Prob(a), Value::Int(b)) => b
721 .cmp_f64(*a)
722 .unwrap_or(Ordering::Less)
723 .reverse()
724 .then_with(|| self.number_rank().cmp(&other.number_rank())),
725 (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
726 (a, b) if ra == 3 => {
727 let (x, y) = (a.as_f64().unwrap(), b.as_f64().unwrap());
729 f64::from_bits(float_key(x))
730 .total_cmp(&f64::from_bits(float_key(y)))
731 .then_with(|| a.number_rank().cmp(&b.number_rank()))
732 .then_with(|| float_key(x).cmp(&float_key(y)))
733 }
734 (Value::Str(a), Value::Str(b)) => a.cmp(b),
735 (Value::Date(a), Value::Date(b)) => a.cmp(b),
736 (Value::Complex(a), Value::Complex(b)) => a.re().total_cmp(&b.re()).then(a.im().total_cmp(&b.im())),
739 (Value::Enum(a), Value::Enum(b)) => (a.ty, a.variant).cmp(&(b.ty, b.variant)),
740 (Value::List(a), Value::List(b)) => a.cmp(b),
741 (Value::Range(a, b), Value::Range(c, d)) => (a, b).cmp(&(c, d)),
742 (Value::Map(a), Value::Map(b)) => a.cmp(b),
743 (Value::Bag(a), Value::Bag(b)) => a.cmp(b),
744 (Value::Record(a), Value::Record(b)) => a.cmp(b),
745 (Value::Dist(a), Value::Dist(b)) => a.cmp(b),
746 (Value::Closure(a), Value::Closure(b)) => a.cmp(b),
747 (Value::Builtin(a), Value::Builtin(b)) => a.cmp(b),
748 (Value::Continuous(a), Value::Continuous(b)) => family_key(a).cmp(&family_key(b)),
749 (Value::Analytic(a), Value::Analytic(b)) => a.key().cmp(&b.key()),
750 (Value::Event(a), Value::Event(b)) => a.key().cmp(&b.key()),
751 (Value::Counts(a), Value::Counts(b)) => a.key().cmp(&b.key()),
752 (Value::Joint(a), Value::Joint(b)) => a.cmp(b),
753 (Value::Delayed(a), Value::Delayed(b)) => {
754 (a.variable, family_key(&a.family)).cmp(&(b.variable, family_key(&b.family)))
755 }
756 _ => Ordering::Equal,
757 }
758 }
759}
760
761impl PartialOrd for Value {
762 fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
763 Some(self.cmp(other))
764 }
765}
766
767pub fn fmt_float(f: f64) -> String {
771 if f.is_nan() {
772 return "nan".into();
773 }
774 if f.is_infinite() {
775 return if f > 0.0 { "inf".into() } else { "-inf".into() };
776 }
777 let a = f.abs();
778 if a != 0.0 && (a >= 1e15 || a < 1e-4) {
779 return format!("{f:e}");
780 }
781 if f == f.trunc() {
782 format!("{f:.1}")
783 } else {
784 format!("{f}")
785 }
786}
787
788pub fn fmt_prob(p: f64) -> String {
790 let pct = p * 100.0;
791 if pct != 0.0 && pct.abs() < 0.01 {
792 return format!("{pct:.1e}%");
793 }
794 let text = format!("{pct:.2}");
795 let text = text.trim_end_matches('0').trim_end_matches('.');
796 format!("{text}%")
797}
798
799impl fmt::Display for Value {
800 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
801 write_value(self, f, false)
802 }
803}
804
805impl fmt::Debug for Value {
806 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
807 write_value(self, f, true)
808 }
809}
810
811fn write_value(v: &Value, f: &mut fmt::Formatter<'_>, nested: bool) -> fmt::Result {
812 match v {
813 Value::Dead => write!(f, "<no value>"),
814 Value::Unit => write!(f, "()"),
815 Value::Int(i) => write!(f, "{i}"),
816 Value::Float(x) => write!(f, "{}", fmt_float(*x)),
817 Value::Complex(z) => write!(f, "complex({}, {})", fmt_float(z.re()), fmt_float(z.im())),
818 Value::Bool(b) => write!(f, "{b}"),
819 Value::Prob(p) => write!(f, "{}", fmt_prob(*p)),
820 Value::Str(s) if nested => write!(f, "{s:?}"),
821 Value::Str(s) => write!(f, "{s}"),
822 Value::List(items) => {
823 write!(f, "[")?;
824 for (i, item) in items.iter().enumerate() {
825 if i > 0 {
826 write!(f, ", ")?;
827 }
828 write_value(item, f, true)?;
829 }
830 write!(f, "]")
831 }
832 Value::Map(m) => {
833 if m.is_empty() {
834 return write!(f, "[:]");
835 }
836 write!(f, "[")?;
837 for (i, (k, v)) in m.iter().enumerate() {
838 if i > 0 {
839 write!(f, ", ")?;
840 }
841 write_value(k, f, true)?;
842 write!(f, ": ")?;
843 write_value(v, f, true)?;
844 }
845 write!(f, "]")
846 }
847 Value::Bag(b) => {
848 write!(f, "bag([")?;
849 for (i, (k, n)) in b.iter().enumerate() {
850 if i > 0 {
851 write!(f, ", ")?;
852 }
853 write_value(k, f, true)?;
854 write!(f, ": {n}")?;
855 }
856 write!(f, "])")
857 }
858 Value::Range(a, b) => write!(f, "{a}..{b}"),
859 Value::Record(r) => {
860 if let Some(t) = &r.ty {
861 write!(f, "{t} ")?;
862 }
863 write!(f, "{{ ")?;
864 for (i, (name, v)) in r.fields.iter().enumerate() {
865 if i > 0 {
866 write!(f, ", ")?;
867 }
868 write!(f, "{name}: ")?;
869 write_value(v, f, true)?;
870 }
871 write!(f, " }}")
872 }
873 Value::Enum(e) => write!(f, "{}", e.name),
874 Value::Dist(d) | Value::Joint(d) => {
875 write!(f, "dist(")?;
876 for (i, (v, p)) in d.outcomes.iter().enumerate() {
877 if i == 8 {
878 write!(f, ", … {} more", d.outcomes.len() - 8)?;
879 break;
880 }
881 if i > 0 {
882 write!(f, ", ")?;
883 }
884 write_value(v, f, true)?;
885 write!(f, ": {}", fmt_prob(*p))?;
886 }
887 write!(f, ")")
888 }
889 Value::Closure(_) | Value::Builtin(_) => write!(f, "<function>"),
890 Value::Date(d) => write!(f, "{}", crate::dates::format(*d)),
891 Value::Continuous(family) => write!(f, "{family}"),
892 Value::Counts(c) => write!(f, "{c}"),
893 Value::Analytic(a) => match a.affine() {
894 Some(g) => write!(f, "<analytic float: {} * {} + {}>", g.scale, a.family, g.offset),
895 None => write!(f, "<analytic float: piecewise in {}>", a.family),
896 },
897 Value::Event(_) => write!(f, "<analytic bool>"),
898 Value::Delayed(d) => write!(f, "<not drawn yet: {}>", d.family),
899 }
900}
901
902#[cfg(test)]
903mod tests {
904 use super::*;
905
906 fn bag(counts: &[(i64, u64)]) -> Multiset {
907 Multiset::new(counts.iter().map(|&(v, n)| (Value::Int(v.into()), n)).collect())
908 }
909
910 #[test]
911 fn a_bag_keeps_its_hash_up_to_date() {
912 let full = bag(&[(1, 2), (2, 1), (3, 4)]);
913 let taken = full
915 .without(&Value::Int(3.into()))
916 .unwrap()
917 .without(&Value::Int(2.into()))
918 .unwrap();
919 let direct = bag(&[(1, 2), (3, 3)]);
920 assert_eq!(taken, direct);
921 assert_eq!(taken.sum, direct.sum);
922 assert!(taken.without(&Value::Int(2.into())).is_none());
923 assert_ne!(bag(&[(1, 2), (2, 3)]).sum, bag(&[(1, 3), (2, 2)]).sum);
925 assert_ne!(bag(&[(1, 1)]).sum, bag(&[(2, 1)]).sum);
926 }
927
928 #[test]
929 fn an_unshared_copy_is_equal_and_separate() {
930 let row = Value::record(Record {
931 ty: Some(Arc::from("Day")),
932 fields: vec![
933 (Arc::from("n"), Value::Int(1.into())),
934 (Arc::from("s"), Value::str("x")),
935 ],
936 });
937 let original = Value::list(vec![row.clone(), row]);
938 let copy = original.unshared();
939 assert_eq!(copy, original);
940 let (Value::List(a), Value::List(b)) = (&original, ©) else {
941 panic!()
942 };
943 assert!(!Arc::ptr_eq(a, b));
944 let (Value::Record(x), Value::Record(y)) = (&a[0], &b[0]) else {
945 panic!()
946 };
947 assert!(!Arc::ptr_eq(x, y));
948 let Value::Record(y2) = &b[1] else { panic!() };
950 assert!(Arc::ptr_eq(&y.fields[0].0, &y2.fields[0].0));
951 assert!(!Arc::ptr_eq(&x.fields[0].0, &y.fields[0].0));
952 }
953
954 #[test]
955 fn a_changed_collection_forgets_its_hash() {
956 let mut list = Hashed::new(vec![Value::Int(1.into())]);
957 let before = list.hash_code();
958 list.push(Value::Int(2.into()));
959 assert_ne!(list.hash_code(), before);
960 assert_eq!(
961 list.hash_code(),
962 Hashed::new(vec![Value::Int(1.into()), Value::Int(2.into())]).hash_code()
963 );
964 assert_ne!(list, Hashed::new(vec![Value::Int(1.into())]));
965 }
966}