/* * Copyright 2025 Casper Dalgaard Nielsen * Adam Yasser Tallouzi * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// This file provides an interface for interacting with `Fixpoint.Ast.Ram.Predicates`./// Core features include providing a list of all `RelSym` in `Predicates`,/// provide the `PredType` of a `RelSym` and transforming `RelSym` of one/// `PredType` into a `RelSym` of another `PredType`.////// The three `PredType`s originate from semi-naive evaluation and are `Full`, `Delta` and `New`/// (delta').////// Instead of adding an enum type (Full/Delta/New) to the predicate, we embed the type into/// the identifier, which we can do since we have an upper bound on the integers used.////// For a `Datalog` AST consisting of predicates `PredSym("Road", 0)` and `PredSym("Path", 1)`/// the RAM has 6 predicates, 3 for each predicate in the `Datalog` AST. Every predicate/// has a `Full` version, a `Delta` version and a `New` version.////// For `PredSym("Road", 0)` the predicates in RAM are `PredSym("Road", 0)`, `PredSym("Road", 2)`,/// and `PredSym("Road", 4)`. `PredSym("Road", 0)` is the full predicate, `PredSym("Road", 2)`/// is the delta predicate and `PredSym("Road", 4)` is the delta' predicate./// For `PredSym("Path", 1)` the predicates in RAM are be `PredSym("Path", 1)`, `PredSym("Path", 3)`,/// and `PredSym("Path", 5)`.////// In the above way `PredType` is encoded in the identifier of a `PredSym`.///pubmod Fixpoint3.Predicate {use Fixpoint3.Ast.Shared.PredSymuse Fixpoint3.Ast.Shared.PredSym.PredSymuse Fixpoint3.Ast.Datalog.Datalog.Dataloguse Fixpoint3.Ast.Datalog.{BodyPredicate, BodyTerm, Constraint, Datalog, HeadPredicate, HeadTerm, Polarity, VarSym}use Fixpoint3.Ast.Datalog.Constraint.Constraintuse Fixpoint3.Ast.Datalog.HeadPredicate.HeadAtomuse Fixpoint3.Ast.Datalog.BodyPredicate.{BodyAtom}use Fixpoint3.Ast.Ram.{BoolExp, Facts, Predicates, RamProgram, RamStmt, RamTerm, RelOp, RelSym, RowVar, toId}use Fixpoint3.Boxed////// `PredType` describes the three types of predicates that exists in a RAM program.////// `Full` relations contains all facts computed for a relation.////// `Delta` relations contains, in iteration `i`, all facts computed in iteration `i-1` in fixpoints computations.////// `New` relations contains, in iteration `i`, all facts computed in iteration `i` in fixpoints computations.///pubenumPredTypewithEq {case Fullcase Deltacase New }////// Returns 1 plus the maximum full predicate in `predicates`.///pubdefgetMax(predicates: Predicates): Int64 = {let (_, _, res) = predicates;res }////// Returns a list of all full `RelSym` in `predInfo`.///pubdefallFullRelSyms(predInfo: Predicates): List[RelSym] =let (_, full, _) = predInfo;full////// Returns a list of all `RelSym` in `predInfo`.///pubdefallRelSyms(predInfo: Predicates): List[RelSym] =let (relSyms, _, _) = predInfo;relSyms////// Returns the full `RelSym` associated with the `PredSym` in `body` according to `predInfo`.///pubdefbodyAtomToRelSym(body: BodyPredicate, wantedType: PredType, predInfo: Predicates): RelSym =letfullRel = bodyAtomToFullRelSym(body);getRelSymAsType(fullRel, wantedType, predInfo)////// Returns the identifier of `wantedType` of `id` according to `predInfo`///deffullIdtoPredType(id: Int64, wantedType: PredType, max: Int64): Int64 =matchwantedType {case PredType.Full => idcase PredType.Delta => id+maxcase PredType.New => id+max*2i64 }////// Returns a `RelSym` of type `wantedType` given the `RelSym` `relSym`, which must be/// a full `RelSym`.///pubdeffullRelSymToType(relSym: RelSym, wantedType: PredType, predInfo: Predicates): RelSym =fullRelSymToTypeInternal(relSym, wantedType, getMax(predInfo))////// Returns a `RelSym` of type `wantedType` given the `RelSym` `relSym`, which must be/// a full `RelSym`.///deffullRelSymToTypeInternal(relSym: RelSym, wantedType: PredType, max: Int64): RelSym = matchrelSym {case RelSym.Symbol(PredSym.PredSym(name, id), arity, den) => RelSym.Symbol(PredSym.PredSym(name, fullIdtoPredType(id, wantedType, max)), arity, den) }////// Returns the identifier of type `wantedType` from `id` according to `predInfo`.///defgetIdAsType(id: Int64, wantedType: PredType, predInfo: Predicates): Int64 =letfullId = idToFullPredId(id, predInfo);fullIdtoPredType(fullId, wantedType, getMax(predInfo))////// Returns the `PredSym` of type `wantedType` from `predSym` according to `predInfo`.///defgetPredSymAsType(predSym: PredSym, wantedType: PredType, predInfo: Predicates): PredSym = matchpredSym {case PredSym.PredSym(name, id) => PredSym.PredSym(name, getIdAsType(id, wantedType, predInfo)) }////// Returns the `RelSym` of type `wantedType` from `relSym` according to `predInfo`.///pubdefgetRelSymAsType(relSym: RelSym, wantedType: PredType, predInfo: Predicates): RelSym = matchrelSym {case RelSym.Symbol(pred, arity, den) => RelSym.Symbol(getPredSymAsType(pred, wantedType, predInfo), arity, den) }////// Returns the full `RelSym` associated with the `PredSym` in `head` according to `predInfo`.///pubdefheadAtomToRelSym(head: HeadPredicate, wantedType: PredType, predInfo: Predicates): RelSym =letfullRel = headAtomToFullRelSym(head);getRelSymAsType(fullRel, wantedType, predInfo)////// Returns the identifier of the full `PredSym` associated with the identifier `id`/// according to `predInfo`.///defidToFullPredId(id: Int64, predInfo: Predicates): Int64 =letmax = getMax(predInfo);if (id<=max) {id } elseif (id<=max*2i64) {id-max } else {id-2i64*max }////// Returns the type of a `PredSym` with identifier `id` according to `predInfo`.///defidToPredType(id: Int64, predInfo: Predicates): PredType =letmax = getMax(predInfo);if (id<=max) { PredType.Full } elseif (id<=max*2i64) { PredType.Delta } else { PredType.New }////// Collect all preciate information given a Datalog program `program` and database `db`.///pubdefinitialize(program: Datalog, db: Map[RelSym, BPlusTree[Vector[Boxed], Boxed, Static]]): Predicates =relSymsOfProgramWithDb(program, db)////// Returns true if `id` is the id of a full `PredSym` according to `predInfo`.///pubdefisFullId(id: Int64, predInfo: Predicates): Bool = PredType.Full ==idToPredType(id, predInfo)////// Returns a `RelSym` of type `wantedType` from `relSym` according to `predInfo`.///pubdefrelSymFromPredType(relSym: RelSym, wantedType: PredType, predInfo: Predicates): RelSym = matchrelSym {case RelSym.Symbol(PredSym.PredSym(name, id), arity, den) => RelSym.Symbol(PredSym.PredSym(name, fullIdtoPredType(idToFullPredId(id, predInfo), wantedType, getMax(predInfo))), arity, den) }////// Returns a list of all `RelSym` known in `program`.///pubdefrelSymsOfProgram(program: RamProgram): List[RelSym] = matchprogram {case RamProgram.Program(_, _, predInfo, _, _) => allRelSyms(predInfo) }////// Returns a list of all `RelSym` known in `program`.///pubdeffullRelSymsOfProgram(program: RamProgram): List[RelSym] = matchprogram {case RamProgram.Program(_, _, predInfo, _, _) => allFullRelSyms(predInfo) }////// Returns the type of the `PredSym` in `relSym` according to `predInfo`.///pubdefrelSymToPredType(relSym: RelSym, predInfo: Predicates): PredType = matchrelSym {case RelSym.Symbol(PredSym.PredSym(_, id), _, _) => idToPredType(id, predInfo) }////// Returns a set of all full `RelSym` created from `PredSym`s in `program` and `db` and the maximal identifier+1.///defrelSymsOfProgramWithDb(program: Datalog, db: Map[RelSym, BPlusTree[Vector[Boxed], Boxed, Static]]): Predicates = matchprogram {case Datalog(facts, rules) =>letset1 = relSymsOf(rules);letset2 = relSymsOf(facts);letset3 = relSymsOfDb(db);letset = (set1`Set.union`set2) `Set.union`set3;letfullRels = Set.toList(set);letoptMax = fullRels |> List.maximumBy(match RelSym.Symbol(PredSym.PredSym(_, id1), _, _) -> match RelSym.Symbol(PredSym.PredSym(_, id2), _, _) -> id1<=>id2);letmax = matchoptMax {case None => 0i64case Some(max) => toId(max) +1i64 };letdeltaRels = List.map(x -> fullRelSymToTypeInternal(x, PredType.Delta, max), fullRels);letnewRels = List.map(x -> fullRelSymToTypeInternal(x, PredType.New, max), fullRels);letallRels = fullRels:::deltaRels:::newRels; (allRels, fullRels, max)case_ => bug!("Datalog Boxing bug") }////// Returns a set of full `RelSym` in `db`.///defrelSymsOfDb(db: Map[RelSym, BPlusTree[Vector[Boxed], Boxed, Static]]): Set[RelSym] =Map.foldLeftWithKey(set -> relSym -> _ -> Set.insert(relSym, set), Set#{}, db)////// Returns a set of full `RelSym` in `constraints`.///defrelSymsOf(constraints: Vector[Constraint]): Set[RelSym] =Vector.foldLeft(matchset -> match Constraint(headAtom, body) -> {letsetWithHead = Set.insert(headAtomToFullRelSym(headAtom), set);Vector.foldLeft(setBody -> bodyConstraint -> matchbodyConstraint {case BodyAtom(_, _, _, _, _) =>Set.insert(bodyAtomToFullRelSym(bodyConstraint), setBody)case_ => setBody },setWithHead,body ) },Set#{},constraints )////// Returns the full `RelSym` associated with the `PredSym` in `head`.///defheadAtomToFullRelSym(head: HeadPredicate): RelSym = matchhead {case HeadAtom(pred, den, terms) => RelSym.Symbol(pred, Vector.length(terms), den) }////// Returns the full `RelSym` associated with the `PredSym` in `body`.///defbodyAtomToFullRelSym(body: BodyPredicate): RelSym = matchbody {case BodyAtom(pred, den, _, _, terms) => RelSym.Symbol(pred, Vector.length(terms), den)case_ => unreachable!() }}