terms/
lib.rs

1extern crate rand;
2
3//use std::rc::Arc;
4use std::sync::Arc;
5use std::hash::{Hash, Hasher};
6use std::cmp::{PartialOrd, Ord, Ordering};
7use std::collections::hash_map::DefaultHasher;
8use std::sync::atomic::{self, AtomicU64};
9use std::fmt;
10
11pub mod pattern;
12pub mod variable;
13pub mod macros;
14mod index;
15
16pub use pattern::{Pattern, PatternKind, PatternLike, PatternLikeKind};
17pub use variable::Var;
18pub use index::*;
19
20pub trait Ranked {
21    fn arity(&self) -> usize;
22}
23
24/// A term.
25///
26/// Subterms are reference counter using [`std::rc::Arc`].
27pub struct Term<F> {
28    f: F,
29    subs: Arc<Vec<Self>>,
30    hash: AtomicU64
31}
32
33impl<F: fmt::Debug> fmt::Debug for Term<F> {
34    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35        write!(f, "{:?}({:?})", self.f, self.subs)
36    }
37}
38
39impl<F: fmt::Display> fmt::Display for Term<F> {
40    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41        self.f.fmt(f)?;
42        match self.subs.split_first() {
43            Some((head, tail)) => {
44                write!(f, "(")?;
45                head.fmt(f)?;
46                for e in tail.iter() {
47                    write!(f, ", ")?;
48                    e.fmt(f)?;
49                }
50                write!(f, ")")
51            },
52            None => Ok(())
53        }
54    }
55}
56
57impl<F> Term<F> {
58    pub fn new(f: F, subs: Vec<Self>) -> Self where F: Clone {
59        Term {
60            f: f,
61            subs: Arc::new(subs),
62            hash: AtomicU64::new(0)
63        }
64    }
65
66    pub fn from_slice(f: F, subs: &[Self]) -> Self where F: Clone {
67        Term {
68            f: f,
69            subs: Arc::new(subs.iter().map(|p| p.clone()).collect()),
70            hash: AtomicU64::new(0)
71        }
72    }
73
74    pub fn symbol(&self) -> &F {
75        &self.f
76    }
77
78    // /// Note that it is unwise to use the hash of the while it is still mutating.
79    // pub fn with_capacity(f: F, capacity: usize) -> Self where F: Clone {
80    //     Term {
81    //         f: f,
82    //         subs: Vec::with_capacity(capacity),
83    //         hash: Cell::new(0)
84    //     }
85    // }
86
87    pub fn sub_terms(&self) -> &Vec<Self> {
88        &self.subs
89    }
90
91    // /// Beware that is may change to term's hash!
92    // pub fn sub_terms_mut(&mut self) -> &mut Vec<Self> {
93    //     self.hash.set(0);
94    //     &mut self.subs
95    // }
96
97    pub fn depth(&self) -> u64 {
98        let mut depth = 0;
99        for sub in self.subs.iter() {
100            let d = sub.depth() + 1;
101            if d > depth {
102                depth = d
103            }
104        }
105
106        depth
107    }
108
109    fn random_with_zeros(zero_alphabet: &[F], alphabet: &[F], max_depth: u64) -> Term<F> where F: Clone + Ranked {
110        let i: usize = rand::random();
111        let (f, arity, next_depth) = if max_depth == 0 {
112            let f: &F = &zero_alphabet[i%zero_alphabet.len()];
113            (f.clone(), 0, 0)
114        } else {
115            let f: &F = &alphabet[i%alphabet.len()];
116            (f.clone(), f.arity(), max_depth-1)
117        };
118
119        let mut subs = Vec::with_capacity(arity);
120        for _ in 0..arity {
121            subs.push(Self::random_with_zeros(zero_alphabet, alphabet, next_depth))
122        }
123
124        Term {
125            f: f,
126            subs: Arc::new(subs),
127            hash: AtomicU64::new(0)
128        }
129    }
130
131    /// Generate a random term with the given alphabet.
132    /// The alphabet must contain at least one constant (of arity 0), otherwise it will panic.
133    pub fn random(alphabet: &[F], max_depth: u64) -> Term<F> where F: Clone + Ranked {
134        let mut zeros = Vec::with_capacity(alphabet.len());
135        for f in alphabet.iter() {
136            if f.arity() == 0 {
137                zeros.push(f.clone())
138            }
139        }
140
141        assert!(!zeros.is_empty());
142        Self::random_with_zeros(&zeros, alphabet, max_depth)
143    }
144}
145
146impl<F, X> PatternLike<F, X> for Term<F> {
147    fn kind(&self) -> PatternLikeKind<F, X, Self> {
148        PatternLikeKind::Cons(&self.f, &self.subs)
149    }
150}
151
152impl<F: Clone> Clone for Term<F> {
153    fn clone(&self) -> Term<F> {
154        Term {
155            f: self.f.clone(),
156            subs: self.subs.clone(),
157            hash: AtomicU64::new(self.hash.load(atomic::Ordering::Relaxed)),
158        }
159    }
160}
161
162impl<F: PartialEq> PartialEq for Term<F> {
163    fn eq(&self, other: &Term<F>) -> bool {
164        self.f == other.f && self.subs == other.subs
165    }
166}
167
168impl<F: PartialEq + Eq> Eq for Term<F> {}
169
170impl<F: Hash> Hash for Term<F> {
171    fn hash<H: Hasher>(&self, state: &mut H) {
172        let mut h = self.hash.load(atomic::Ordering::Relaxed);
173        if h == 1 { // hash is beeing computed by another thread.
174            loop {
175                h = self.hash.load(atomic::Ordering::Relaxed);
176                if h != 1 {
177                    break;
178                }
179            }
180        }
181        if h == 0 {
182            //self.hash.set(1); // set to 1 to avoid loops.
183            self.hash.store(1, atomic::Ordering::Relaxed);
184
185            let mut hasher = DefaultHasher::new();
186            self.f.hash(&mut hasher);
187            for sub in self.subs.iter() {
188                Term::<F>::hash(sub, &mut hasher)
189            }
190            h = hasher.finish();
191            if h <= 1 { // just to be sure...
192                h = 2;
193            }
194            self.hash.store(h, atomic::Ordering::Relaxed);
195        }
196        h.hash(state)
197    }
198}
199
200impl<F: Ord> PartialOrd for Term<F> {
201    fn partial_cmp(&self, other: &Term<F>) -> Option<Ordering> {
202        Some(self.cmp(other))
203    }
204}
205
206impl<F: Ord> Ord for Term<F> {
207    fn cmp(&self, other: &Term<F>) -> Ordering {
208        match self.depth().cmp(&other.depth()) {
209            Ordering::Equal => {
210                match self.f.cmp(&other.f) {
211                    Ordering::Equal => {
212                        match self.subs.len().cmp(&other.subs.len()) {
213                            Ordering::Equal => {
214                                for (i, a) in self.subs.iter().enumerate() {
215                                    let b = &other.subs[i];
216                                    match a.cmp(b) {
217                                        Ordering::Equal => (),
218                                        ord => return ord
219                                    }
220                                }
221
222                                Ordering::Equal
223                            },
224                            ord => ord
225                        }
226                    },
227                    ord =>  ord
228                }
229            },
230            ord => ord
231        }
232    }
233}