use crate::enforcement::{
BindingEntry, BindingsTable, CompileUnit, CompletenessCertificate, ConstrainedTypeInput,
GenericImpossibilityWitness, Grounded, GroundingCertificate, InhabitanceCertificate,
InhabitanceImpossibilityWitness, LiftChainCertificate, MacroProvenance, PipelineFailure,
ShapeViolation, Validated,
};
use crate::ViolationKind;
use crate::WittLevel;
pub const PREFLIGHT_CHECK_IRIS: &[&str] = &[
"https://uor.foundation/reduction/BudgetSolvencyCheck",
"https://uor.foundation/reduction/FeasibilityCheck",
"https://uor.foundation/reduction/DispatchCoverageCheck",
"https://uor.foundation/reduction/PackageCoherenceCheck",
"https://uor.foundation/reduction/PreflightTiming",
"https://uor.foundation/reduction/RuntimeTiming",
];
pub const REDUCTION_STAGE_IRIS: &[&str] = &[
"https://uor.foundation/reduction/stage_initialization",
"https://uor.foundation/reduction/stage_declare",
"https://uor.foundation/reduction/stage_factorize",
"https://uor.foundation/reduction/stage_resolve",
"https://uor.foundation/reduction/stage_attest",
"https://uor.foundation/reduction/stage_extract",
"https://uor.foundation/reduction/stage_convergence",
];
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum ConstraintRef {
Residue { modulus: u64, residue: u64 },
Hamming { bound: u32 },
Depth { min: u32, max: u32 },
Carry { site: u32 },
Site { position: u32 },
Affine {
coefficients: &'static [i64],
bias: i64,
},
SatClauses {
clauses: &'static [&'static [(u32, bool)]],
num_vars: u32,
},
}
#[doc(hidden)]
pub mod constrained_type_shape_sealed {
pub trait Sealed {}
impl Sealed for super::ConstrainedTypeInput {}
}
pub trait ConstrainedTypeShape: constrained_type_shape_sealed::Sealed {
const IRI: &'static str;
const SITE_COUNT: usize;
const CONSTRAINTS: &'static [ConstraintRef];
}
impl ConstrainedTypeShape for ConstrainedTypeInput {
const IRI: &'static str = "https://uor.foundation/type/ConstrainedType";
const SITE_COUNT: usize = 0;
const CONSTRAINTS: &'static [ConstraintRef] = &[];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FragmentKind {
TwoSat,
Horn,
Residual,
}
#[must_use]
pub const fn fragment_classify(constraints: &[ConstraintRef]) -> FragmentKind {
let mut i = 0;
while i < constraints.len() {
if let ConstraintRef::SatClauses { clauses, .. } = constraints[i] {
let mut max_width: usize = 0;
let mut horn: bool = true;
let mut j = 0;
while j < clauses.len() {
let clause = clauses[j];
if clause.len() > max_width {
max_width = clause.len();
}
let mut positives: usize = 0;
let mut k = 0;
while k < clause.len() {
let (_, negated) = clause[k];
if !negated {
positives += 1;
}
k += 1;
}
if positives > 1 {
horn = false;
}
j += 1;
}
if max_width <= 2 {
return FragmentKind::TwoSat;
} else if horn {
return FragmentKind::Horn;
} else {
return FragmentKind::Residual;
}
}
i += 1;
}
FragmentKind::Residual
}
const TWO_SAT_MAX_VARS: usize = 256;
const TWO_SAT_MAX_NODES: usize = TWO_SAT_MAX_VARS * 2;
const TWO_SAT_MAX_EDGES: usize = 2048;
#[must_use]
pub fn decide_two_sat(clauses: &[&[(u32, bool)]], num_vars: u32) -> bool {
if (num_vars as usize) > TWO_SAT_MAX_VARS {
return false;
}
let n = (num_vars as usize) * 2;
let mut adj_starts = [0usize; TWO_SAT_MAX_NODES + 1];
let mut adj_targets = [0usize; TWO_SAT_MAX_EDGES];
for clause in clauses {
if clause.len() > 2 || clause.is_empty() {
return false;
}
if clause.len() == 1 {
let (v, neg) = clause[0];
let lit = lit_index(v, neg);
let neg_lit = lit_index(v, !neg);
if neg_lit < n + 1 {
adj_starts[neg_lit + 1] += 1;
}
let _ = lit;
} else {
let (a, an) = clause[0];
let (b, bn) = clause[1];
let na = lit_index(a, !an);
let nb = lit_index(b, !bn);
if na + 1 < n + 1 {
adj_starts[na + 1] += 1;
}
if nb + 1 < n + 1 {
adj_starts[nb + 1] += 1;
}
}
}
let mut i = 1;
while i <= n {
adj_starts[i] += adj_starts[i - 1];
i += 1;
}
let edge_count = adj_starts[n];
if edge_count > TWO_SAT_MAX_EDGES {
return false;
}
let mut fill = [0usize; TWO_SAT_MAX_NODES];
for clause in clauses {
if clause.len() == 1 {
let (v, neg) = clause[0];
let pos_lit = lit_index(v, neg);
let neg_lit = lit_index(v, !neg);
let slot = adj_starts[neg_lit] + fill[neg_lit];
adj_targets[slot] = pos_lit;
fill[neg_lit] += 1;
} else {
let (a, an) = clause[0];
let (b, bn) = clause[1];
let pa = lit_index(a, an);
let na = lit_index(a, !an);
let pb = lit_index(b, bn);
let nb = lit_index(b, !bn);
let s1 = adj_starts[na] + fill[na];
adj_targets[s1] = pb;
fill[na] += 1;
let s2 = adj_starts[nb] + fill[nb];
adj_targets[s2] = pa;
fill[nb] += 1;
}
}
let mut index_counter: usize = 0;
let mut indices = [usize::MAX; TWO_SAT_MAX_NODES];
let mut lowlinks = [0usize; TWO_SAT_MAX_NODES];
let mut on_stack = [false; TWO_SAT_MAX_NODES];
let mut stack = [0usize; TWO_SAT_MAX_NODES];
let mut stack_top: usize = 0;
let mut scc_id = [usize::MAX; TWO_SAT_MAX_NODES];
let mut scc_count: usize = 0;
let mut call_stack = [(0usize, 0usize); TWO_SAT_MAX_NODES];
let mut call_top: usize = 0;
let mut v = 0;
while v < n {
if indices[v] == usize::MAX {
call_stack[call_top] = (v, adj_starts[v]);
call_top += 1;
indices[v] = index_counter;
lowlinks[v] = index_counter;
index_counter += 1;
stack[stack_top] = v;
stack_top += 1;
on_stack[v] = true;
while call_top > 0 {
let (u, mut next_edge) = call_stack[call_top - 1];
let end_edge = adj_starts[u + 1];
let mut advanced = false;
while next_edge < end_edge {
let w = adj_targets[next_edge];
next_edge += 1;
if indices[w] == usize::MAX {
call_stack[call_top - 1] = (u, next_edge);
indices[w] = index_counter;
lowlinks[w] = index_counter;
index_counter += 1;
stack[stack_top] = w;
stack_top += 1;
on_stack[w] = true;
call_stack[call_top] = (w, adj_starts[w]);
call_top += 1;
advanced = true;
break;
} else if on_stack[w] && indices[w] < lowlinks[u] {
lowlinks[u] = indices[w];
}
}
if !advanced {
call_stack[call_top - 1] = (u, next_edge);
if lowlinks[u] == indices[u] {
loop {
stack_top -= 1;
let w = stack[stack_top];
on_stack[w] = false;
scc_id[w] = scc_count;
if w == u {
break;
}
}
scc_count += 1;
}
call_top -= 1;
if call_top > 0 {
let (parent, _) = call_stack[call_top - 1];
if lowlinks[u] < lowlinks[parent] {
lowlinks[parent] = lowlinks[u];
}
}
}
}
}
v += 1;
}
let mut var = 0u32;
while var < num_vars {
let pos = lit_index(var, false);
let neg = lit_index(var, true);
if scc_id[pos] == scc_id[neg] {
return false;
}
var += 1;
}
true
}
#[inline]
const fn lit_index(var: u32, negated: bool) -> usize {
let base = (var as usize) * 2;
if negated {
base + 1
} else {
base
}
}
const HORN_MAX_VARS: usize = 256;
#[must_use]
pub fn decide_horn_sat(clauses: &[&[(u32, bool)]], num_vars: u32) -> bool {
if (num_vars as usize) > HORN_MAX_VARS {
return false;
}
let mut assignment = [false; HORN_MAX_VARS];
let n = num_vars as usize;
loop {
let mut changed = false;
for clause in clauses {
let mut positive: Option<u32> = None;
let mut positive_count = 0;
for (_, negated) in clause.iter() {
if !*negated {
positive_count += 1;
}
}
if positive_count > 1 {
return false;
}
for (var, negated) in clause.iter() {
if !*negated {
positive = Some(*var);
}
}
let mut all_neg_satisfied = true;
for (var, negated) in clause.iter() {
if *negated {
let idx = *var as usize;
if idx >= n {
return false;
}
if !assignment[idx] {
all_neg_satisfied = false;
break;
}
}
}
if all_neg_satisfied {
match positive {
None => return false,
Some(v) => {
let idx = v as usize;
if idx >= n {
return false;
}
if !assignment[idx] {
assignment[idx] = true;
changed = true;
}
}
}
}
}
if !changed {
break;
}
}
for clause in clauses {
let mut satisfied = false;
for (var, negated) in clause.iter() {
let idx = *var as usize;
if idx >= n {
return false;
}
let val = assignment[idx];
if (*negated && !val) || (!*negated && val) {
satisfied = true;
break;
}
}
if !satisfied {
return false;
}
}
true
}
#[must_use]
pub const fn hash_constraints(iri: &str, site_count: usize, constraints: &[ConstraintRef]) -> u128 {
let mut hash: u128 = 0x6c62272e07bb014262b821756295c58d;
let iri_bytes = iri.as_bytes();
let mut i = 0;
while i < iri_bytes.len() {
hash ^= iri_bytes[i] as u128;
hash = hash.wrapping_mul(0x0000000001000000000000000000013b);
i += 1;
}
hash ^= site_count as u128;
hash = hash.wrapping_mul(0x0000000001000000000000000000013b);
hash ^= constraints.len() as u128;
hash = hash.wrapping_mul(0x0000000001000000000000000000013b);
hash
}
pub fn preflight_budget_solvency(budget_units: u64, witt_bits: u32) -> Result<(), ShapeViolation> {
let minimum = witt_bits as u64;
if budget_units >= minimum {
Ok(())
} else {
Err(ShapeViolation {
shape_iri: "https://uor.foundation/conformance/CompileUnitShape",
constraint_iri:
"https://uor.foundation/conformance/compileUnit_thermodynamicBudget_constraint",
property_iri: "https://uor.foundation/reduction/thermodynamicBudget",
expected_range: "http://www.w3.org/2001/XMLSchema#decimal",
min_count: 1,
max_count: 1,
kind: ViolationKind::ValueCheck,
})
}
}
pub fn preflight_feasibility(constraints: &[ConstraintRef]) -> Result<(), ShapeViolation> {
for c in constraints {
if let ConstraintRef::SatClauses { clauses, num_vars } = c {
if *num_vars == 0 && !clauses.is_empty() {
return Err(ShapeViolation {
shape_iri: "https://uor.foundation/conformance/CompileUnitShape",
constraint_iri:
"https://uor.foundation/conformance/compileUnit_rootTerm_constraint",
property_iri: "https://uor.foundation/reduction/rootTerm",
expected_range: "https://uor.foundation/schema/Term",
min_count: 1,
max_count: 1,
kind: ViolationKind::ValueCheck,
});
}
}
}
Ok(())
}
pub fn preflight_dispatch_coverage() -> Result<(), ShapeViolation> {
Ok(())
}
pub fn preflight_package_coherence(constraints: &[ConstraintRef]) -> Result<(), ShapeViolation> {
let mut i = 0;
while i < constraints.len() {
if let ConstraintRef::Residue {
modulus: m1,
residue: r1,
} = constraints[i]
{
let mut j = i + 1;
while j < constraints.len() {
if let ConstraintRef::Residue {
modulus: m2,
residue: r2,
} = constraints[j]
{
if m1 == m2 && r1 != r2 {
return Err(ShapeViolation {
shape_iri: "https://uor.foundation/conformance/CompileUnitShape",
constraint_iri:
"https://uor.foundation/conformance/compileUnit_rootTerm_constraint",
property_iri: "https://uor.foundation/reduction/rootTerm",
expected_range: "https://uor.foundation/schema/Term",
min_count: 1,
max_count: 1,
kind: ViolationKind::ValueCheck,
});
}
}
j += 1;
}
}
i += 1;
}
Ok(())
}
#[allow(dead_code)]
const PREFLIGHT_BUDGET_NS: u64 = 10000000;
pub fn preflight_timing() -> Result<(), ShapeViolation> {
Ok(())
}
#[allow(dead_code)]
const RUNTIME_BUDGET_NS: u64 = 10000000;
pub fn runtime_timing() -> Result<(), ShapeViolation> {
Ok(())
}
#[derive(Debug, Clone, Copy)]
pub struct StageOutcome {
pub unit_address: u128,
pub witt_bits: u16,
pub fragment: FragmentKind,
pub satisfiable: bool,
}
pub fn run_reduction_stages<T: ConstrainedTypeShape + ?Sized>(
_input: &T,
witt_bits: u16,
) -> Result<StageOutcome, PipelineFailure> {
let unit_address = hash_constraints(T::IRI, T::SITE_COUNT, T::CONSTRAINTS);
let fragment = fragment_classify(T::CONSTRAINTS);
let satisfiable = match fragment {
FragmentKind::TwoSat => {
let mut sat = true;
for c in T::CONSTRAINTS {
if let ConstraintRef::SatClauses { clauses, num_vars } = c {
sat = decide_two_sat(clauses, *num_vars);
break;
}
}
sat
}
FragmentKind::Horn => {
let mut sat = true;
for c in T::CONSTRAINTS {
if let ConstraintRef::SatClauses { clauses, num_vars } = c {
sat = decide_horn_sat(clauses, *num_vars);
break;
}
}
sat
}
FragmentKind::Residual => {
let mut has_sat_clauses = false;
for c in T::CONSTRAINTS {
if matches!(c, ConstraintRef::SatClauses { .. }) {
has_sat_clauses = true;
break;
}
}
!has_sat_clauses
}
};
if matches!(fragment, FragmentKind::Residual) && !satisfiable {
return Err(PipelineFailure::ConvergenceStall {
stage_iri: "https://uor.foundation/reduction/stage_convergence",
angle_milliradians: 0,
});
}
Ok(StageOutcome {
unit_address,
witt_bits,
fragment,
satisfiable,
})
}
pub fn run_tower_completeness<T: ConstrainedTypeShape + ?Sized>(
input: &T,
level: WittLevel,
) -> Result<Validated<LiftChainCertificate>, GenericImpossibilityWitness> {
let witt_bits = level.witt_length() as u16;
preflight_budget_solvency(witt_bits as u64, witt_bits as u32)
.map_err(|_| GenericImpossibilityWitness::default())?;
preflight_feasibility(T::CONSTRAINTS).map_err(|_| GenericImpossibilityWitness::default())?;
preflight_package_coherence(T::CONSTRAINTS)
.map_err(|_| GenericImpossibilityWitness::default())?;
preflight_dispatch_coverage().map_err(|_| GenericImpossibilityWitness::default())?;
preflight_timing().map_err(|_| GenericImpossibilityWitness::default())?;
runtime_timing().map_err(|_| GenericImpossibilityWitness::default())?;
let outcome = run_reduction_stages(input, witt_bits)
.map_err(|_| GenericImpossibilityWitness::default())?;
if outcome.satisfiable {
let prov = MacroProvenance::__for_macro_crate();
let cert = LiftChainCertificate::with_witt_bits(outcome.witt_bits);
Ok(crate::enforcement::__uor_macro_mint_validated(prov, cert))
} else {
Err(GenericImpossibilityWitness::default())
}
}
pub fn run_incremental_completeness<T: ConstrainedTypeShape + ?Sized>(
input: &T,
level: WittLevel,
) -> Result<Validated<LiftChainCertificate>, GenericImpossibilityWitness> {
run_tower_completeness(input, level)
}
pub fn run_grounding_aware(
_input: &CompileUnit,
level: WittLevel,
) -> Result<Validated<GroundingCertificate>, GenericImpossibilityWitness> {
let witt_bits = level.witt_length() as u16;
let prov = MacroProvenance::__for_macro_crate();
let cert = GroundingCertificate::with_witt_bits(witt_bits);
Ok(crate::enforcement::__uor_macro_mint_validated(prov, cert))
}
pub fn run_inhabitance<T: ConstrainedTypeShape + ?Sized>(
input: &T,
level: WittLevel,
) -> Result<Validated<InhabitanceCertificate>, InhabitanceImpossibilityWitness> {
let witt_bits = level.witt_length() as u16;
preflight_budget_solvency(witt_bits as u64, witt_bits as u32)
.map_err(|_| InhabitanceImpossibilityWitness::default())?;
preflight_feasibility(T::CONSTRAINTS)
.map_err(|_| InhabitanceImpossibilityWitness::default())?;
preflight_package_coherence(T::CONSTRAINTS)
.map_err(|_| InhabitanceImpossibilityWitness::default())?;
preflight_dispatch_coverage().map_err(|_| InhabitanceImpossibilityWitness::default())?;
preflight_timing().map_err(|_| InhabitanceImpossibilityWitness::default())?;
runtime_timing().map_err(|_| InhabitanceImpossibilityWitness::default())?;
let outcome = run_reduction_stages(input, witt_bits)
.map_err(|_| InhabitanceImpossibilityWitness::default())?;
if outcome.satisfiable {
let prov = MacroProvenance::__for_macro_crate();
let cert = InhabitanceCertificate::with_witt_bits(outcome.witt_bits);
Ok(crate::enforcement::__uor_macro_mint_validated(prov, cert))
} else {
Err(InhabitanceImpossibilityWitness::default())
}
}
pub fn run_pipeline<T: ConstrainedTypeShape + crate::enforcement::GroundedShape>(
input: &T,
witt_bits: u16,
) -> Result<Grounded<T>, PipelineFailure> {
preflight_budget_solvency(witt_bits as u64, witt_bits as u32)
.map_err(|report| PipelineFailure::ShapeViolation { report })?;
preflight_feasibility(T::CONSTRAINTS)
.map_err(|report| PipelineFailure::ShapeViolation { report })?;
preflight_package_coherence(T::CONSTRAINTS)
.map_err(|report| PipelineFailure::ShapeViolation { report })?;
preflight_dispatch_coverage().map_err(|report| PipelineFailure::ShapeViolation { report })?;
preflight_timing().map_err(|report| PipelineFailure::ShapeViolation { report })?;
runtime_timing().map_err(|report| PipelineFailure::ShapeViolation { report })?;
let outcome = run_reduction_stages(input, witt_bits)?;
if !outcome.satisfiable {
return Err(PipelineFailure::ContradictionDetected {
at_step: 0,
trace_iri: "https://uor.foundation/trace/InhabitanceSearchTrace",
});
}
let prov = MacroProvenance::__for_macro_crate();
let grounding =
crate::enforcement::__uor_macro_mint_validated(prov, GroundingCertificate::default());
let bindings = empty_bindings_table();
Ok(crate::enforcement::__uor_macro_mint_grounded::<T>(
MacroProvenance::__for_macro_crate(),
grounding,
bindings,
outcome.witt_bits,
outcome.unit_address,
))
}
#[must_use]
pub const fn empty_bindings_table() -> BindingsTable {
BindingsTable::new(&[])
}
#[allow(dead_code)]
const _BINDING_ENTRY_REF: Option<BindingEntry> = None;
#[allow(dead_code)]
const _COMPLETENESS_CERT_REF: Option<CompletenessCertificate> = None;