1mod triblesetconstraint;
2pub mod triblesetidrangeconstraint;
3pub mod triblesetrangeconstraint;
4
5use triblesetconstraint::*;
6
7use crate::query::TriblePattern;
8use crate::inline::Inline;
9
10use crate::id::Id;
11use crate::patch::ArchiveEntry;
12use crate::patch::Entry;
13use crate::patch::PATCH;
14use crate::query::Variable;
15use crate::trible::AEVOrder;
16use crate::trible::AVEOrder;
17use crate::trible::EAVOrder;
18use crate::trible::EVAOrder;
19use crate::trible::Trible;
20use crate::trible::VAEOrder;
21use crate::trible::VEAOrder;
22use crate::trible::TRIBLE_LEN;
23use crate::inline::encodings::genid::GenId;
24use crate::inline::InlineEncoding;
25
26use std::iter::FromIterator;
27use std::iter::Map;
28use std::ops::Add;
29use std::ops::AddAssign;
30
31#[derive(Debug, Clone)]
46pub struct TribleSet {
47 pub eav: PATCH<TRIBLE_LEN, EAVOrder, ()>,
49 pub vea: PATCH<TRIBLE_LEN, VEAOrder, ()>,
51 pub ave: PATCH<TRIBLE_LEN, AVEOrder, ()>,
53 pub vae: PATCH<TRIBLE_LEN, VAEOrder, ()>,
55 pub eva: PATCH<TRIBLE_LEN, EVAOrder, ()>,
57 pub aev: PATCH<TRIBLE_LEN, AEVOrder, ()>,
59}
60
61#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
66pub struct TribleSetFingerprint(Option<u128>);
67
68impl TribleSetFingerprint {
69 pub const EMPTY: Self = Self(None);
71
72 pub fn is_empty(self) -> bool {
74 self.0.is_none()
75 }
76
77 pub fn as_u128(self) -> Option<u128> {
79 self.0
80 }
81}
82
83type TribleSetInner<'a> =
84 Map<crate::patch::PATCHIterator<'a, 64, EAVOrder, ()>, fn(&[u8; 64]) -> &Trible>;
85
86pub struct TribleSetIterator<'a> {
88 inner: TribleSetInner<'a>,
89}
90
91#[cfg(feature = "parallel")]
95pub const PARALLEL_UNION_THRESHOLD: usize = 4096;
96
97impl TribleSet {
98 pub fn union(&mut self, other: Self) {
113 #[cfg(feature = "parallel")]
114 {
115 if other.len() >= PARALLEL_UNION_THRESHOLD {
116 let Self {
117 eav,
118 eva,
119 aev,
120 ave,
121 vea,
122 vae,
123 } = self;
124 let Self {
125 eav: oeav,
126 eva: oeva,
127 aev: oaev,
128 ave: oave,
129 vea: ovea,
130 vae: ovae,
131 } = other;
132 rayon::join(
135 || rayon::join(
136 || eav.union(oeav),
137 || eva.union(oeva),
138 ),
139 || rayon::join(
140 || rayon::join(
141 || aev.union(oaev),
142 || ave.union(oave),
143 ),
144 || rayon::join(
145 || vea.union(ovea),
146 || vae.union(ovae),
147 ),
148 ),
149 );
150 return;
151 }
152 }
153
154 self.eav.union(other.eav);
155 self.eva.union(other.eva);
156 self.aev.union(other.aev);
157 self.ave.union(other.ave);
158 self.vea.union(other.vea);
159 self.vae.union(other.vae);
160 }
161
162 pub fn intersect(&self, other: &Self) -> Self {
170 #[cfg(feature = "parallel")]
171 {
172 if self.len().min(other.len()) >= PARALLEL_UNION_THRESHOLD {
173 let ((eav, eva), ((aev, ave), (vea, vae))) = rayon::join(
174 || {
175 rayon::join(
176 || self.eav.intersect(&other.eav),
177 || self.eva.intersect(&other.eva),
178 )
179 },
180 || {
181 rayon::join(
182 || {
183 rayon::join(
184 || self.aev.intersect(&other.aev),
185 || self.ave.intersect(&other.ave),
186 )
187 },
188 || {
189 rayon::join(
190 || self.vea.intersect(&other.vea),
191 || self.vae.intersect(&other.vae),
192 )
193 },
194 )
195 },
196 );
197 return Self {
198 eav,
199 eva,
200 aev,
201 ave,
202 vea,
203 vae,
204 };
205 }
206 }
207 Self {
208 eav: self.eav.intersect(&other.eav),
209 eva: self.eva.intersect(&other.eva),
210 aev: self.aev.intersect(&other.aev),
211 ave: self.ave.intersect(&other.ave),
212 vea: self.vea.intersect(&other.vea),
213 vae: self.vae.intersect(&other.vae),
214 }
215 }
216
217 pub fn difference(&self, other: &Self) -> Self {
225 #[cfg(feature = "parallel")]
226 {
227 if self.len() >= PARALLEL_UNION_THRESHOLD {
228 let ((eav, eva), ((aev, ave), (vea, vae))) = rayon::join(
229 || {
230 rayon::join(
231 || self.eav.difference(&other.eav),
232 || self.eva.difference(&other.eva),
233 )
234 },
235 || {
236 rayon::join(
237 || {
238 rayon::join(
239 || self.aev.difference(&other.aev),
240 || self.ave.difference(&other.ave),
241 )
242 },
243 || {
244 rayon::join(
245 || self.vea.difference(&other.vea),
246 || self.vae.difference(&other.vae),
247 )
248 },
249 )
250 },
251 );
252 return Self {
253 eav,
254 eva,
255 aev,
256 ave,
257 vea,
258 vae,
259 };
260 }
261 }
262 Self {
263 eav: self.eav.difference(&other.eav),
264 eva: self.eva.difference(&other.eva),
265 aev: self.aev.difference(&other.aev),
266 ave: self.ave.difference(&other.ave),
267 vea: self.vea.difference(&other.vea),
268 vae: self.vae.difference(&other.vae),
269 }
270 }
271
272 pub fn new() -> TribleSet {
274 TribleSet {
275 eav: PATCH::<TRIBLE_LEN, EAVOrder, ()>::new(),
276 eva: PATCH::<TRIBLE_LEN, EVAOrder, ()>::new(),
277 aev: PATCH::<TRIBLE_LEN, AEVOrder, ()>::new(),
278 ave: PATCH::<TRIBLE_LEN, AVEOrder, ()>::new(),
279 vea: PATCH::<TRIBLE_LEN, VEAOrder, ()>::new(),
280 vae: PATCH::<TRIBLE_LEN, VAEOrder, ()>::new(),
281 }
282 }
283
284 pub fn len(&self) -> usize {
286 self.eav.len() as usize
287 }
288
289 pub fn is_empty(&self) -> bool {
291 self.len() == 0
292 }
293
294 pub fn fingerprint(&self) -> TribleSetFingerprint {
299 TribleSetFingerprint(self.eav.root_hash())
300 }
301
302 pub fn insert(&mut self, trible: &Trible) {
304 let key = Entry::new(&trible.data);
305 self.eav.insert(&key);
306 self.eva.insert(&key);
307 self.aev.insert(&key);
308 self.ave.insert(&key);
309 self.vea.insert(&key);
310 self.vae.insert(&key);
311 }
312
313 pub fn insert_archive(&mut self, entry: &ArchiveEntry<'_, TRIBLE_LEN>) {
319 self.eav.insert_archive(entry);
320 self.eva.insert_archive(entry);
321 self.aev.insert_archive(entry);
322 self.ave.insert_archive(entry);
323 self.vea.insert_archive(entry);
324 self.vae.insert_archive(entry);
325 }
326
327 pub fn contains(&self, trible: &Trible) -> bool {
329 self.eav.has_prefix(&trible.data)
330 }
331
332 pub fn value_in_range<V: InlineEncoding>(
346 &self,
347 variable: Variable<V>,
348 min: Inline<V>,
349 max: Inline<V>,
350 ) -> triblesetrangeconstraint::TribleSetRangeConstraint {
351 triblesetrangeconstraint::TribleSetRangeConstraint::new(variable, min, max, self.clone())
352 }
353
354 pub fn entity_in_range(
366 &self,
367 variable: Variable<GenId>,
368 min: Id,
369 max: Id,
370 ) -> triblesetidrangeconstraint::EntityRangeConstraint {
371 triblesetidrangeconstraint::EntityRangeConstraint::new(variable, min, max, self.clone())
372 }
373
374 pub fn attribute_in_range(
386 &self,
387 variable: Variable<GenId>,
388 min: Id,
389 max: Id,
390 ) -> triblesetidrangeconstraint::AttributeRangeConstraint {
391 triblesetidrangeconstraint::AttributeRangeConstraint::new(variable, min, max, self.clone())
392 }
393
394 pub fn iter(&self) -> TribleSetIterator<'_> {
396 TribleSetIterator {
397 inner: self
398 .eav
399 .iter()
400 .map(|data| Trible::as_transmute_raw_unchecked(data)),
401 }
402 }
403}
404
405impl PartialEq for TribleSet {
406 fn eq(&self, other: &Self) -> bool {
407 self.eav == other.eav
408 }
409}
410
411impl Eq for TribleSet {}
412
413impl Default for TribleSetFingerprint {
414 fn default() -> Self {
415 Self::EMPTY
416 }
417}
418
419impl From<&TribleSet> for TribleSetFingerprint {
420 fn from(set: &TribleSet) -> Self {
421 set.fingerprint()
422 }
423}
424
425impl AddAssign for TribleSet {
426 fn add_assign(&mut self, rhs: Self) {
427 self.union(rhs);
428 }
429}
430
431impl Add for TribleSet {
432 type Output = Self;
433
434 fn add(mut self, rhs: Self) -> Self::Output {
435 self.union(rhs);
436 self
437 }
438}
439
440impl FromIterator<Trible> for TribleSet {
441 fn from_iter<I: IntoIterator<Item = Trible>>(iter: I) -> Self {
442 let mut set = TribleSet::new();
443
444 for t in iter {
445 set.insert(&t);
446 }
447
448 set
449 }
450}
451
452impl TriblePattern for TribleSet {
453 type PatternConstraint<'a> = TribleSetConstraint;
454
455 fn pattern<V: InlineEncoding>(
456 &self,
457 e: Variable<GenId>,
458 a: Variable<GenId>,
459 v: Variable<V>,
460 ) -> Self::PatternConstraint<'static> {
461 TribleSetConstraint::new(e, a, v, self.clone())
462 }
463}
464
465impl<'a> Iterator for TribleSetIterator<'a> {
466 type Item = &'a Trible;
467
468 fn next(&mut self) -> Option<Self::Item> {
469 self.inner.next()
470 }
471}
472
473impl<'a> IntoIterator for &'a TribleSet {
474 type Item = &'a Trible;
475 type IntoIter = TribleSetIterator<'a>;
476
477 fn into_iter(self) -> Self::IntoIter {
478 self.iter()
479 }
480}
481
482impl Default for TribleSet {
483 fn default() -> Self {
484 Self::new()
485 }
486}
487
488#[cfg(test)]
489mod tests {
490 use crate::examples::literature;
491 use crate::prelude::*;
492
493 use super::*;
494 use fake::faker::lorem::en::Words;
495 use fake::faker::name::raw::FirstName;
496 use fake::faker::name::raw::LastName;
497 use fake::locales::EN;
498 use fake::Fake;
499
500 use rayon::iter::IntoParallelIterator;
501 use rayon::iter::ParallelIterator;
502
503 #[test]
504 fn union() {
505 let mut kb = TribleSet::new();
506 for _i in 0..100 {
507 let author = ufoid();
508 let book = ufoid();
509 kb += entity! { &author @
510 literature::firstname: FirstName(EN).fake::<String>(),
511 literature::lastname: LastName(EN).fake::<String>(),
512 };
513 kb += entity! { &book @
514 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
515 literature::author: &author
516 };
517 }
518 assert_eq!(kb.len(), 400);
519 }
520
521 #[test]
522 fn union_parallel() {
523 let kb = (0..1000)
524 .into_par_iter()
525 .flat_map(|_| {
526 let author = ufoid();
527 let book = ufoid();
528 [
529 entity! { &author @
530 literature::firstname: FirstName(EN).fake::<String>(),
531 literature::lastname: LastName(EN).fake::<String>(),
532 },
533 entity! { &book @
534 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
535 literature::author: &author
536 },
537 ]
538 })
539 .reduce(Fragment::default, |a, b| a + b);
540 assert_eq!(kb.len(), 4000);
541 }
542
543 #[test]
544 fn intersection() {
545 let mut kb1 = TribleSet::new();
546 let mut kb2 = TribleSet::new();
547 for _i in 0..100 {
548 let author = ufoid();
549 let book = ufoid();
550 kb1 += entity! { &author @
551 literature::firstname: FirstName(EN).fake::<String>(),
552 literature::lastname: LastName(EN).fake::<String>(),
553 };
554 kb1 += entity! { &book @
555 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
556 literature::author: &author
557 };
558 kb2 += entity! { &author @
559 literature::firstname: FirstName(EN).fake::<String>(),
560 literature::lastname: LastName(EN).fake::<String>(),
561 };
562 kb2 += entity! { &book @
563 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
564 literature::author: &author
565 };
566 }
567 let intersection = kb1.intersect(&kb2);
568 for trible in &intersection {
570 assert!(kb1.contains(trible));
571 assert!(kb2.contains(trible));
572 }
573 }
574
575 #[test]
576 fn difference() {
577 let mut kb1 = TribleSet::new();
578 let mut kb2 = TribleSet::new();
579 for _i in 0..100 {
580 let author = ufoid();
581 let book = ufoid();
582 kb1 += entity! { &author @
583 literature::firstname: FirstName(EN).fake::<String>(),
584 literature::lastname: LastName(EN).fake::<String>(),
585 };
586 kb1 += entity! { &book @
587 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
588 literature::author: &author
589 };
590 if _i % 2 == 0 {
591 kb2 += entity! { &author @
592 literature::firstname: FirstName(EN).fake::<String>(),
593 literature::lastname: LastName(EN).fake::<String>(),
594 };
595 kb2 += entity! { &book @
596 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
597 literature::author: &author
598 };
599 }
600 }
601 let difference = kb1.difference(&kb2);
602 for trible in &difference {
604 assert!(kb1.contains(trible));
605 assert!(!kb2.contains(trible));
606 }
607 }
608
609 #[test]
610 fn test_contains() {
611 let mut kb = TribleSet::new();
612 let author = ufoid();
613 let book = ufoid();
614 let author_tribles = entity! { &author @
615 literature::firstname: FirstName(EN).fake::<String>(),
616 literature::lastname: LastName(EN).fake::<String>(),
617 };
618 let book_tribles = entity! { &book @
619 literature::title: Words(1..3).fake::<Vec<String>>().join(" "),
620 literature::author: &author
621 };
622
623 kb += author_tribles.clone();
624 kb += book_tribles.clone();
625
626 for trible in &author_tribles {
627 assert!(kb.contains(trible));
628 }
629 for trible in &book_tribles {
630 assert!(kb.contains(trible));
631 }
632
633 let non_existent_trible = entity! { &ufoid() @
634 literature::firstname: FirstName(EN).fake::<String>(),
635 literature::lastname: LastName(EN).fake::<String>(),
636 };
637
638 for trible in &non_existent_trible {
639 assert!(!kb.contains(trible));
640 }
641 }
642}