aboutsummaryrefslogtreecommitdiffstats
path: root/lib/constraint.ml
diff options
context:
space:
mode:
authorMarcos Magueta <maguetamarcos@gmail.com>2026-03-08 20:48:14 -0300
committerMarcos Magueta <maguetamarcos@gmail.com>2026-03-08 20:48:14 -0300
commitcce3bfba31b32c13ea116a214306d96fe1eb27eb (patch)
treea572e969d7c53686e047764b7fba3e52d3589215 /lib/constraint.ml
parent88dc315e454a695426becf928aef46668f9db0dc (diff)
downloadSakura-cce3bfba31b32c13ea116a214306d96fe1eb27eb.tar.gz
Sakura-cce3bfba31b32c13ea116a214306d96fe1eb27eb.zip
format todos and comment improvement
Diffstat (limited to '')
-rw-r--r--lib/constraint.ml129
1 files changed, 26 insertions, 103 deletions
diff --git a/lib/constraint.ml b/lib/constraint.ml
index b7844eb..42f8f88 100644
--- a/lib/constraint.ml
+++ b/lib/constraint.ml
@@ -7,10 +7,14 @@
Negation requires an explicit universe relation name, forcing
closed-world reasoning in first-order logic. *)
+(* TODO: lt/lte/gt/gte/eq/neq/between at the bottom reference target names
+ like "less_than" that don't match the prelude relation names
+ (e.g. "natural_natural_less_than"). These constructors are currently dead
+ code and will fail at runtime if used. *)
+
type relation_name = string
type attr_name = string
-(** Binding expressions resolve against a tuple's attributes *)
type binding_expr =
| Var of attr_name
| Const of Conventions.AbstractValue.t
@@ -27,10 +31,6 @@ type t =
| Exists of { variable : attr_name; quantifier : relation_name; body : t }
| Forall of { variable : attr_name; quantifier : relation_name; body : t }
-(* ============================================================================
- Diagnostics
- ============================================================================ *)
-
type diagnostic =
| MembershipFailed of {
target : string;
@@ -43,11 +43,6 @@ type diagnostic =
}
| ConstraintFailures of (string * diagnostic) list
-(* ============================================================================
- Utility functions
- ============================================================================ *)
-
-(** Collect all [Var] names referenced in a constraint *)
let rec vars_in : t -> attr_name list = function
| MemberOf { binding; _ } ->
BindingMap.fold
@@ -63,7 +58,6 @@ let rec vars_in : t -> attr_name list = function
if List.mem variable inner then inner
else variable :: inner
-(** Rename [Var] references according to a rename list *)
let rec rename_vars (renames : (attr_name * attr_name) list) : t -> t = function
| MemberOf { target; binding } ->
let binding' =
@@ -94,16 +88,14 @@ let rec rename_vars (renames : (attr_name * attr_name) list) : t -> t = function
| Some n -> n
| None -> variable
in
- Exists
- { variable = variable'; quantifier; body = rename_vars renames body }
+ Exists { variable = variable'; quantifier; body = rename_vars renames body }
| Forall { variable; quantifier; body } ->
let variable' =
match List.assoc_opt variable renames with
| Some n -> n
| None -> variable
in
- Forall
- { variable = variable'; quantifier; body = rename_vars renames body }
+ Forall { variable = variable'; quantifier; body = rename_vars renames body }
(** Drop constraints referencing attributes not in the given set.
Returns [None] if the constraint cannot be kept. *)
@@ -121,7 +113,7 @@ let rec filter_by_attrs (attrs : attr_name list) (c : t) : t option =
let kept = List.filter_map (filter_by_attrs attrs) cs in
if kept = [] then None else Some (And kept)
| Or cs ->
- (* For Or, all branches must survive *)
+ (* All branches must survive for Or to remain sound *)
let kept = List.filter_map (filter_by_attrs attrs) cs in
if List.length kept = List.length cs then Some (Or kept) else None
| Exists { variable; quantifier; body } -> (
@@ -133,11 +125,9 @@ let rec filter_by_attrs (attrs : attr_name list) (c : t) : t option =
| Some body' -> Some (Forall { variable; quantifier; body = body' })
| None -> None)
-(** AND-merge two named constraint lists *)
let merge (cs1 : (string * t) list) (cs2 : (string * t) list)
: (string * t) list =
let combined = cs1 @ cs2 in
- (* Group by name and AND-merge duplicates *)
let tbl = Hashtbl.create 16 in
List.iter
(fun (name, c) ->
@@ -151,33 +141,12 @@ let merge (cs1 : (string * t) list) (cs2 : (string * t) list)
(name, merged) :: acc)
tbl []
-(* ============================================================================
- Smart constructors
- ============================================================================ *)
-
let member_of ~target ~binding = MemberOf { target; binding }
-
let not_ ~universe body = Not { body; universe }
-
-let and_ cs =
- match cs with
- | [ c ] -> c
- | _ -> And cs
-
-let or_ cs =
- match cs with
- | [ c ] -> c
- | _ -> Or cs
-
-let exists ~variable ~quantifier body =
- Exists { variable; quantifier; body }
-
-let forall ~variable ~quantifier body =
- Forall { variable; quantifier; body }
-
-(* ============================================================================
- Evaluation context (no dependency on Relation/Database/Manipulation)
- ============================================================================ *)
+let and_ cs = match cs with [ c ] -> c | _ -> And cs
+let or_ cs = match cs with [ c ] -> c | _ -> Or cs
+let exists ~variable ~quantifier body = Exists { variable; quantifier; body }
+let forall ~variable ~quantifier body = Forall { variable; quantifier; body }
type eval_context = {
check_membership :
@@ -189,11 +158,6 @@ type eval_context = {
(attr_name * Conventions.AbstractValue.t) list list option;
}
-(* ============================================================================
- Binding resolution
- ============================================================================ *)
-
-(** Resolve binding expressions against a materialized tuple *)
let bind (b : binding) (tuple : Tuple.materialized)
: (attr_name * Conventions.AbstractValue.t) list =
BindingMap.fold
@@ -211,13 +175,6 @@ let bind (b : binding) (tuple : Tuple.materialized)
| None -> acc)
b []
-(* ============================================================================
- Constraint evaluation
- ============================================================================ *)
-
-(** Evaluate a constraint against a tuple in the given context.
- Returns [Ok true] if satisfied, [Ok false] should not occur —
- failures return [Error diagnostic]. *)
let rec evaluate (ctx : eval_context) (tuple : Tuple.materialized) (c : t)
: (bool, diagnostic) result =
match c with
@@ -227,9 +184,8 @@ let rec evaluate (ctx : eval_context) (tuple : Tuple.materialized) (c : t)
else Error (MembershipFailed { target; bound_values })
| Not { body; universe = _ } ->
(* The universe is a declarative annotation for closed-world reasoning.
- At runtime, we simply negate the body. The universe ensures logical
- soundness at the schema level, not as a runtime tuple-existence check
- (the tuple being validated hasn't been stored yet). *)
+ At runtime we negate the body; the universe enforces logical soundness
+ at the schema level, not as a runtime tuple-existence check. *)
(match evaluate ctx tuple body with
| Ok true -> Ok false
| Ok false -> Ok true
@@ -239,13 +195,11 @@ let rec evaluate (ctx : eval_context) (tuple : Tuple.materialized) (c : t)
| Or cs -> evaluate_or ctx tuple cs
| Exists { variable; quantifier; body } -> (
match ctx.iterate_finite quantifier with
- | None ->
- Error (UnboundedQuantifier { variable; quantifier })
+ | None -> Error (UnboundedQuantifier { variable; quantifier })
| Some rows ->
let rec check = function
| [] -> Ok false
| row :: rest ->
- (* Bind the quantifier variable into scope *)
let extended_tuple = extend_tuple tuple variable row in
(match evaluate ctx extended_tuple body with
| Ok true -> Ok true
@@ -255,8 +209,7 @@ let rec evaluate (ctx : eval_context) (tuple : Tuple.materialized) (c : t)
check rows)
| Forall { variable; quantifier; body } -> (
match ctx.iterate_finite quantifier with
- | None ->
- Error (UnboundedQuantifier { variable; quantifier })
+ | None -> Error (UnboundedQuantifier { variable; quantifier })
| Some rows ->
let rec check = function
| [] -> Ok true
@@ -286,9 +239,6 @@ and evaluate_or ctx tuple = function
| Ok false -> evaluate_or ctx tuple rest
| Error _ -> evaluate_or ctx tuple rest)
-(** Extend a tuple with bindings from a quantifier row.
- Each row entry [(attr, value)] gets added with [variable] as prefix
- if the attr name doesn't match an existing attribute. *)
and extend_tuple (tuple : Tuple.materialized)
(_variable : attr_name)
(row : (attr_name * Conventions.AbstractValue.t) list)
@@ -301,7 +251,6 @@ and extend_tuple (tuple : Tuple.materialized)
in
{ tuple with attributes = extra_attrs }
-(** Evaluate a list of named constraints, collecting all failures *)
let evaluate_named (ctx : eval_context) (tuple : Tuple.materialized)
(named : (string * t) list) : (bool, diagnostic) result =
let failures =
@@ -318,59 +267,33 @@ let evaluate_named (ctx : eval_context) (tuple : Tuple.materialized)
| [] -> Ok true
| fs -> Error (ConstraintFailures fs)
-(* ============================================================================
- Comparison shorthand constructors
- ============================================================================ *)
-
let make_comparison_binding ~left ~right =
BindingMap.empty
|> BindingMap.add "left" left
|> BindingMap.add "right" right
let lt ~left ~right =
- MemberOf
- { target = "less_than"; binding = make_comparison_binding ~left ~right }
+ MemberOf { target = "less_than"; binding = make_comparison_binding ~left ~right }
let lte ~left ~right =
- MemberOf
- {
- target = "less_than_or_equal";
- binding = make_comparison_binding ~left ~right;
- }
+ MemberOf { target = "less_than_or_equal"; binding = make_comparison_binding ~left ~right }
let gt ~left ~right =
- MemberOf
- {
- target = "greater_than";
- binding = make_comparison_binding ~left ~right;
- }
+ MemberOf { target = "greater_than"; binding = make_comparison_binding ~left ~right }
let gte ~left ~right =
- MemberOf
- {
- target = "greater_than_or_equal";
- binding = make_comparison_binding ~left ~right;
- }
+ MemberOf { target = "greater_than_or_equal"; binding = make_comparison_binding ~left ~right }
let eq ~left ~right =
- MemberOf
- { target = "equal"; binding = make_comparison_binding ~left ~right }
+ MemberOf { target = "equal"; binding = make_comparison_binding ~left ~right }
let neq ~left ~right =
- MemberOf
- { target = "not_equal"; binding = make_comparison_binding ~left ~right }
+ MemberOf { target = "not_equal"; binding = make_comparison_binding ~left ~right }
let between ~value ~low ~high =
And
- [
- MemberOf
- {
- target = "greater_than_or_equal";
- binding = make_comparison_binding ~left:value ~right:low;
- };
- MemberOf
- {
- target = "less_than_or_equal";
- binding = make_comparison_binding ~left:value ~right:high;
- };
+ [ MemberOf { target = "greater_than_or_equal";
+ binding = make_comparison_binding ~left:value ~right:low }
+ ; MemberOf { target = "less_than_or_equal";
+ binding = make_comparison_binding ~left:value ~right:high }
]