conjure_cp_core/ast/
declaration.rs

1pub mod serde;
2
3use std::any::TypeId;
4// allow use of Declaration in this file, and nowhere else
5use std::cell::{Cell, Ref, RefCell, RefMut};
6use std::fmt::{Debug, Display};
7use std::rc::Rc;
8
9use ::serde::{Deserialize, Serialize};
10
11use super::categories::{Category, CategoryOf};
12use super::name::Name;
13use super::serde::{DefaultWithId, HasId, ObjId};
14use super::{
15    DecisionVariable, DomainPtr, Expression, GroundDomain, Moo, RecordEntry, ReturnType, Typeable,
16};
17use crate::ast::domains::HasDomain;
18use uniplate::{Biplate, Tree, Uniplate};
19
20thread_local! {
21    // make each thread have its own id counter.
22    static DECLARATION_PTR_ID_COUNTER: Cell<u32> = const { Cell::new(0) };
23
24    // We run integration tests in parallel threads - making this thread local ensures that
25    // declarations in a test always have the same id, instead of the ids depending on how many
26    // threads are running, how they are scheduled, etc.
27}
28
29#[doc(hidden)]
30/// Resets the id counter of `DeclarationPtr` to 0.
31///
32/// This is probably always a bad idea.
33pub fn reset_declaration_id_unchecked() {
34    DECLARATION_PTR_ID_COUNTER.set(0);
35}
36
37/// A shared pointer to a [`Declaration`].
38///
39/// Two declaration pointers are equal if they point to the same underlying declaration.
40///
41/// # Id
42///
43///  The id of `DeclarationPtr` obeys the following invariants:
44///
45/// 1. Declaration pointers have the same id if they point to the same
46///    underlying declaration.
47///
48/// 2. The id is immutable.
49///
50/// 3. Changing the declaration pointed to by the declaration pointer does not change the id. This
51///    allows declarations to be updated by replacing them with a newer version of themselves.
52///
53/// `Ord`, `Hash`, and `Eq` use id for comparisons.
54/// # Serde
55///
56/// Declaration pointers can be serialised using the following serializers:
57///
58/// + [`DeclarationPtrFull`](serde::DeclarationPtrFull)
59/// + [`DeclarationPtrAsId`](serde::DeclarationPtrAsId)
60///
61/// See their documentation for more information.
62#[derive(Clone, Debug)]
63pub struct DeclarationPtr {
64    // the shared bits of the pointer
65    inner: Rc<DeclarationPtrInner>,
66}
67
68// The bits of a declaration that are shared between all pointers.
69#[derive(Clone, Debug)]
70struct DeclarationPtrInner {
71    // We don't want this to be mutable, as `HashMap` and `BTreeMap` rely on the hash or order of
72    // keys to be unchanging.
73    //
74    // See:  https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
75    id: ObjId,
76
77    // The contents of the declaration itself should be mutable.
78    value: RefCell<Declaration>,
79}
80
81impl DeclarationPtrInner {
82    fn new(value: RefCell<Declaration>) -> Rc<DeclarationPtrInner> {
83        Rc::new(DeclarationPtrInner {
84            id: DECLARATION_PTR_ID_COUNTER.replace(DECLARATION_PTR_ID_COUNTER.get() + 1),
85            value,
86        })
87    }
88
89    // SAFETY: only use if you are really really sure you arn't going to break the id invariants of
90    // DeclarationPtr and HasId!
91    fn new_with_id_unchecked(value: RefCell<Declaration>, id: ObjId) -> Rc<DeclarationPtrInner> {
92        Rc::new(DeclarationPtrInner { id, value })
93    }
94}
95
96#[allow(dead_code)]
97impl DeclarationPtr {
98    /******************************/
99    /*        Constructors        */
100    /******************************/
101
102    /// Creates a `DeclarationPtr` for the given `Declaration`.
103    fn from_declaration(declaration: Declaration) -> DeclarationPtr {
104        DeclarationPtr {
105            inner: DeclarationPtrInner::new(RefCell::new(declaration)),
106        }
107    }
108
109    /// Creates a new declaration.
110    ///
111    /// # Examples
112    ///
113    /// ```
114    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
115    ///
116    /// // letting MyDomain be int(1..5)
117    /// let declaration = DeclarationPtr::new(
118    ///     Name::User("MyDomain".into()),
119    ///     DeclarationKind::DomainLetting(Domain::int(vec![
120    ///         Range::Bounded(1,5)])));
121    /// ```
122    pub fn new(name: Name, kind: DeclarationKind) -> DeclarationPtr {
123        DeclarationPtr::from_declaration(Declaration::new(name, kind))
124    }
125
126    /// Creates a new decision variable declaration with the decision category.
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
132    ///
133    /// // find x: int(1..5)
134    /// let declaration = DeclarationPtr::new_var(
135    ///     Name::User("x".into()),
136    ///     Domain::int(vec![Range::Bounded(1,5)]));
137    ///
138    /// ```
139    pub fn new_var(name: Name, domain: DomainPtr) -> DeclarationPtr {
140        let kind =
141            DeclarationKind::DecisionVariable(DecisionVariable::new(domain, Category::Decision));
142        DeclarationPtr::new(name, kind)
143    }
144
145    /// Creates a new decision variable with the quantified category.
146    ///
147    /// This is useful to represent a quantified / induction variable in a comprehension.
148    pub fn new_var_quantified(name: Name, domain: DomainPtr) -> DeclarationPtr {
149        let kind =
150            DeclarationKind::DecisionVariable(DecisionVariable::new(domain, Category::Quantified));
151
152        DeclarationPtr::new(name, kind)
153    }
154
155    /// Creates a new domain letting declaration.
156    ///
157    /// # Examples
158    ///
159    /// ```
160    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
161    ///
162    /// // letting MyDomain be int(1..5)
163    /// let declaration = DeclarationPtr::new_domain_letting(
164    ///     Name::User("MyDomain".into()),
165    ///     Domain::int(vec![Range::Bounded(1,5)]));
166    ///
167    /// ```
168    pub fn new_domain_letting(name: Name, domain: DomainPtr) -> DeclarationPtr {
169        let kind = DeclarationKind::DomainLetting(domain);
170        DeclarationPtr::new(name, kind)
171    }
172
173    /// Creates a new value letting declaration.
174    ///
175    /// # Examples
176    ///
177    /// ```
178    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range, Expression,
179    /// Literal,Atom,Moo};
180    /// use conjure_cp_core::{matrix_expr,ast::Metadata};
181    ///
182    /// // letting n be 10 + 10
183    /// let ten = Expression::Atomic(Metadata::new(),Atom::Literal(Literal::Int(10)));
184    /// let expression = Expression::Sum(Metadata::new(),Moo::new(matrix_expr![ten.clone(),ten]));
185    /// let declaration = DeclarationPtr::new_value_letting(
186    ///     Name::User("n".into()),
187    ///     expression);
188    ///
189    /// ```
190    pub fn new_value_letting(name: Name, expression: Expression) -> DeclarationPtr {
191        let kind = DeclarationKind::ValueLetting(expression);
192        DeclarationPtr::new(name, kind)
193    }
194
195    /// Creates a new given declaration.
196    ///
197    /// # Examples
198    ///
199    /// ```
200    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
201    ///
202    /// // given n: int(1..5)
203    /// let declaration = DeclarationPtr::new_given(
204    ///     Name::User("n".into()),
205    ///     Domain::int(vec![Range::Bounded(1,5)]));
206    ///
207    /// ```
208    pub fn new_given(name: Name, domain: DomainPtr) -> DeclarationPtr {
209        let kind = DeclarationKind::Given(domain);
210        DeclarationPtr::new(name, kind)
211    }
212
213    /// Creates a new record field declaration.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// use conjure_cp_core::ast::{DeclarationPtr,Name,RecordEntry,Domain,Range};
219    ///
220    /// // create declaration for field A in `find rec: record {A: int(0..1), B: int(0..2)}`
221    ///
222    /// let field = RecordEntry {
223    ///     name: Name::User("n".into()),
224    ///     domain: Domain::int(vec![Range::Bounded(1,5)])
225    /// };
226    ///
227    /// let declaration = DeclarationPtr::new_record_field(field);
228    /// ```
229    pub fn new_record_field(entry: RecordEntry) -> DeclarationPtr {
230        let kind = DeclarationKind::RecordField(entry.domain);
231        DeclarationPtr::new(entry.name, kind)
232    }
233
234    /**********************************************/
235    /*        Declaration accessor methods        */
236    /**********************************************/
237
238    /// Gets the domain of the declaration, if it has one.
239    ///
240    /// # Examples
241    ///
242    /// ```
243    /// use conjure_cp_core::ast::{DeclarationPtr, Name, Domain, Range, GroundDomain};
244    ///
245    /// // find a: int(1..5)
246    /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
247    ///
248    /// assert!(declaration.domain().is_some_and(|x| x.as_ground().unwrap() == &GroundDomain::Int(vec![Range::Bounded(1,5)])))
249    ///
250    /// ```
251    pub fn domain(&self) -> Option<DomainPtr> {
252        match &self.kind() as &DeclarationKind {
253            DeclarationKind::DecisionVariable(var) => Some(var.domain_of()),
254            DeclarationKind::ValueLetting(e) => e.domain_of(),
255            DeclarationKind::DomainLetting(domain) => Some(domain.clone()),
256            DeclarationKind::Given(domain) => Some(domain.clone()),
257            DeclarationKind::RecordField(domain) => Some(domain.clone()),
258        }
259    }
260
261    /// Gets the domain of the declaration and fully resolve it
262    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
263        self.domain()?.resolve()
264    }
265
266    /// Gets the kind of the declaration.
267    ///
268    /// # Examples
269    ///
270    /// ```
271    /// use conjure_cp_core::ast::{DeclarationPtr,DeclarationKind,Name,Domain,Range};
272    ///
273    /// // find a: int(1..5)
274    /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
275    /// assert!(matches!(&declaration.kind() as &DeclarationKind, DeclarationKind::DecisionVariable(_)))
276    /// ```
277    pub fn kind(&self) -> Ref<'_, DeclarationKind> {
278        self.map(|x| &x.kind)
279    }
280
281    /// Gets the name of the declaration.
282    ///
283    /// # Examples
284    ///
285    /// ```
286    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
287    ///
288    /// // find a: int(1..5)
289    /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
290    ///
291    /// assert_eq!(&declaration.name() as &Name, &Name::User("a".into()))
292    /// ```
293    pub fn name(&self) -> Ref<'_, Name> {
294        self.map(|x| &x.name)
295    }
296
297    /// This declaration as a decision variable, if it is one.
298    pub fn as_var(&self) -> Option<Ref<'_, DecisionVariable>> {
299        Ref::filter_map(self.borrow(), |x| {
300            if let DeclarationKind::DecisionVariable(var) = &x.kind {
301                Some(var)
302            } else {
303                None
304            }
305        })
306        .ok()
307    }
308
309    /// This declaration as a mutable decision variable, if it is one.
310    pub fn as_var_mut(&mut self) -> Option<RefMut<'_, DecisionVariable>> {
311        RefMut::filter_map(self.borrow_mut(), |x| {
312            if let DeclarationKind::DecisionVariable(var) = &mut x.kind {
313                Some(var)
314            } else {
315                None
316            }
317        })
318        .ok()
319    }
320
321    /// This declaration as a domain letting, if it is one.
322    pub fn as_domain_letting(&self) -> Option<Ref<'_, DomainPtr>> {
323        Ref::filter_map(self.borrow(), |x| {
324            if let DeclarationKind::DomainLetting(domain) = &x.kind {
325                Some(domain)
326            } else {
327                None
328            }
329        })
330        .ok()
331    }
332
333    /// This declaration as a mutable domain letting, if it is one.
334    pub fn as_domain_letting_mut(&mut self) -> Option<RefMut<'_, DomainPtr>> {
335        RefMut::filter_map(self.borrow_mut(), |x| {
336            if let DeclarationKind::DomainLetting(domain) = &mut x.kind {
337                Some(domain)
338            } else {
339                None
340            }
341        })
342        .ok()
343    }
344
345    /// This declaration as a value letting, if it is one.
346    pub fn as_value_letting(&self) -> Option<Ref<'_, Expression>> {
347        Ref::filter_map(self.borrow(), |x| {
348            if let DeclarationKind::ValueLetting(e) = &x.kind {
349                Some(e)
350            } else {
351                None
352            }
353        })
354        .ok()
355    }
356
357    /// This declaration as a mutable value letting, if it is one.
358    pub fn as_value_letting_mut(&mut self) -> Option<RefMut<'_, Expression>> {
359        RefMut::filter_map(self.borrow_mut(), |x| {
360            if let DeclarationKind::ValueLetting(e) = &mut x.kind {
361                Some(e)
362            } else {
363                None
364            }
365        })
366        .ok()
367    }
368
369    /// Changes the name in this declaration, returning the old one.
370    ///
371    /// # Examples
372    ///
373    /// ```
374    /// use conjure_cp_core::ast::{DeclarationPtr, Domain, Range, Name};
375    ///
376    /// // find a: int(1..5)
377    /// let mut declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
378    ///
379    /// let old_name = declaration.replace_name(Name::User("b".into()));
380    /// assert_eq!(old_name,Name::User("a".into()));
381    /// assert_eq!(&declaration.name() as &Name,&Name::User("b".into()));
382    /// ```
383    pub fn replace_name(&mut self, name: Name) -> Name {
384        let mut decl = self.borrow_mut();
385        std::mem::replace(&mut decl.name, name)
386    }
387
388    /*****************************************/
389    /*        Pointer utility methods        */
390    /*****************************************/
391
392    // These are mostly wrappers over RefCell, Ref, and RefMut methods, re-exported here for
393    // convenience.
394
395    /// Immutably borrows the declaration.
396    fn borrow(&self) -> Ref<'_, Declaration> {
397        // unlike refcell.borrow(), this never panics
398        self.inner.value.borrow()
399    }
400
401    /// Mutably borrows the declaration.
402    fn borrow_mut(&mut self) -> RefMut<'_, Declaration> {
403        // unlike refcell.borrow_mut(), this never panics
404        self.inner.value.borrow_mut()
405    }
406
407    /// Creates a new declaration pointer with the same contents as `self` that is not shared with
408    /// anyone else.
409    ///
410    /// As the resulting pointer is unshared, it will have a new id.
411    ///
412    /// # Examples
413    ///
414    /// ```
415    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
416    ///
417    /// // find a: int(1..5)
418    /// let declaration = DeclarationPtr::new_var(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
419    ///
420    /// let mut declaration2 = declaration.clone();
421    ///
422    /// declaration2.replace_name(Name::User("b".into()));
423    ///
424    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
425    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
426    ///
427    /// declaration2 = declaration2.detach();
428    ///
429    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
430    ///
431    /// declaration2.replace_name(Name::User("c".into()));
432    ///
433    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
434    /// assert_eq!(&declaration2.name() as &Name, &Name::User("c".into()));
435    /// ```
436    pub fn detach(self) -> DeclarationPtr {
437        // despite having the same contents, the new declaration pointer is unshared, so it should
438        // get a new id.
439        DeclarationPtr {
440            inner: DeclarationPtrInner::new(self.inner.value.clone()),
441        }
442    }
443
444    /// Applies `f` to the declaration, returning the result as a reference.
445    fn map<U>(&self, f: impl FnOnce(&Declaration) -> &U) -> Ref<'_, U> {
446        Ref::map(self.borrow(), f)
447    }
448
449    /// Applies mutable function `f` to the declaration, returning the result as a mutable reference.
450    fn map_mut<U>(&mut self, f: impl FnOnce(&mut Declaration) -> &mut U) -> RefMut<'_, U> {
451        RefMut::map(self.borrow_mut(), f)
452    }
453
454    /// Replaces the declaration with a new one, returning the old value, without deinitialising
455    /// either one.
456    fn replace(&mut self, declaration: Declaration) -> Declaration {
457        self.inner.value.replace(declaration)
458    }
459}
460
461impl CategoryOf for DeclarationPtr {
462    fn category_of(&self) -> Category {
463        match &self.kind() as &DeclarationKind {
464            DeclarationKind::DecisionVariable(decision_variable) => decision_variable.category_of(),
465            DeclarationKind::ValueLetting(expression) => expression.category_of(),
466            DeclarationKind::DomainLetting(_) => Category::Constant,
467            DeclarationKind::Given(_) => Category::Parameter,
468            DeclarationKind::RecordField(_) => Category::Bottom,
469        }
470    }
471}
472impl HasId for DeclarationPtr {
473    fn id(&self) -> ObjId {
474        self.inner.id
475    }
476}
477
478impl DefaultWithId for DeclarationPtr {
479    fn default_with_id(id: ObjId) -> Self {
480        DeclarationPtr {
481            inner: DeclarationPtrInner::new_with_id_unchecked(
482                RefCell::new(Declaration {
483                    name: Name::User("_UNKNOWN".into()),
484                    kind: DeclarationKind::ValueLetting(false.into()),
485                }),
486                id,
487            ),
488        }
489    }
490}
491
492impl Typeable for DeclarationPtr {
493    fn return_type(&self) -> ReturnType {
494        match &self.kind() as &DeclarationKind {
495            DeclarationKind::DecisionVariable(var) => var.return_type(),
496            DeclarationKind::ValueLetting(expression) => expression.return_type(),
497            DeclarationKind::DomainLetting(domain) => domain.return_type(),
498            DeclarationKind::Given(domain) => domain.return_type(),
499            DeclarationKind::RecordField(domain) => domain.return_type(),
500        }
501    }
502}
503
504impl Uniplate for DeclarationPtr {
505    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
506        let decl = self.borrow();
507        let (tree, recons) = Biplate::<DeclarationPtr>::biplate(&decl as &Declaration);
508
509        let self2 = self.clone();
510        (
511            tree,
512            Box::new(move |x| {
513                let mut self3 = self2.clone();
514                let inner = recons(x);
515                *(&mut self3.borrow_mut() as &mut Declaration) = inner;
516                self3
517            }),
518        )
519    }
520}
521
522impl<To> Biplate<To> for DeclarationPtr
523where
524    Declaration: Biplate<To>,
525    To: Uniplate,
526{
527    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
528        if TypeId::of::<To>() == TypeId::of::<Self>() {
529            unsafe {
530                let self_as_to = std::mem::transmute::<&Self, &To>(self).clone();
531                (
532                    Tree::One(self_as_to),
533                    Box::new(move |x| {
534                        let Tree::One(x) = x else { panic!() };
535
536                        let x_as_self = std::mem::transmute::<&To, &Self>(&x);
537                        x_as_self.clone()
538                    }),
539                )
540            }
541        } else {
542            // call biplate on the enclosed declaration
543            let decl = self.borrow();
544            let (tree, recons) = Biplate::<To>::biplate(&decl as &Declaration);
545
546            let self2 = self.clone();
547            (
548                tree,
549                Box::new(move |x| {
550                    let mut self3 = self2.clone();
551                    let inner = recons(x);
552                    *(&mut self3.borrow_mut() as &mut Declaration) = inner;
553                    self3
554                }),
555            )
556        }
557    }
558}
559
560impl Ord for DeclarationPtr {
561    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
562        self.inner.id.cmp(&other.inner.id)
563    }
564}
565
566impl PartialOrd for DeclarationPtr {
567    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
568        Some(self.cmp(other))
569    }
570}
571
572impl PartialEq for DeclarationPtr {
573    fn eq(&self, other: &Self) -> bool {
574        self.inner.id == other.inner.id
575    }
576}
577
578impl Eq for DeclarationPtr {}
579
580impl std::hash::Hash for DeclarationPtr {
581    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
582        // invariant: x == y -> hash(x) == hash(y)
583        self.inner.id.hash(state);
584    }
585}
586
587impl Display for DeclarationPtr {
588    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
589        let value: &Declaration = &self.borrow();
590        value.fmt(f)
591    }
592}
593
594#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq, Uniplate)]
595#[biplate(to=Expression)]
596#[biplate(to=DeclarationPtr)]
597#[biplate(to=Name)]
598/// The contents of a declaration
599struct Declaration {
600    /// The name of the declared symbol.
601    name: Name,
602
603    /// The kind of the declaration.
604    kind: DeclarationKind,
605}
606
607impl Declaration {
608    /// Creates a new declaration.
609    fn new(name: Name, kind: DeclarationKind) -> Declaration {
610        Declaration { name, kind }
611    }
612}
613
614/// A specific kind of declaration.
615#[non_exhaustive]
616#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
617#[biplate(to=Expression)]
618#[biplate(to=DeclarationPtr)]
619#[biplate(to=Declaration)]
620pub enum DeclarationKind {
621    DecisionVariable(DecisionVariable),
622    ValueLetting(Expression),
623    DomainLetting(DomainPtr),
624    Given(DomainPtr),
625
626    /// A named field inside a record type.
627    /// e.g. A, B in record{A: int(0..1), B: int(0..2)}
628    RecordField(DomainPtr),
629}