gargamelle-model-0.1.0.0: src/Gargamelle/Model/Satisfaction.hs
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
module Gargamelle.Model.Satisfaction
( Evidence(..)
, Verifier(..)
, evalVerifier
, inspectVerifierPlan
, SatisfactionIso(..)
, verifyPredicate
) where
import Data.Kind (Type)
import Data.Void (Void, absurd)
import Data.Functor.Contravariant (Contravariant(..))
import Data.Functor.Contravariant.Divisible (Divisible(..), Decidable(..))
import Gargamelle.Logic.Defunctionalize (ObsMor(..), evalObsMor, inspectObsMor)
{- Note [Free Verifier AST and Algebraic Counterexample Evidence]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[tag:note-free-verifier-ast]
Standard formal verification libraries typically define satisfaction as a predicate returning
an uninformative Boolean:
models :: Model -> Formula -> Bool
When verification fails (returns 'False'), this creates three severe shortcomings:
1. No Explanatory Witness: The caller cannot determine which sub-clause or invariant failed.
2. Loss of Repair Direction: In CEGIS (Counterexample-Guided Inductive Synthesis) loops,
an autonomous agent cannot synthesize a targeted fix without knowing the exact counterexample.
3. No Compositional Accumulation: Multiple independent failures collapse to 'False',
discarding diagnostic information.
Gargamelle replaces opaque booleans with 'Evidence', which forms an algebraic Monoid:
- 'VerifiedSection' is the neutral identity element (mempty).
- 'Counterexample sym witness' records the exact violated symbol and diagnostic witness.
- Composition ('<>') accumulates distinct failure points across conjunctions.
Furthermore, 'Verifier model' is formulated as an observable free 'Divisible' and 'Decidable'
contravariant functor:
- Product conjunctions ('divide') and sum branchings ('choose') are reified as explicit
GADT constructors ('DivideV', 'ChooseV') parameterized over 'ObsMor' rather than opaque
Haskell lambdas.
- Autonomous agents can statically inspect the full verification tree via 'inspectVerifierPlan'
without needing a runtime model.
- Evaluation via 'evalVerifier' executes the AST and produces structured 'Evidence'.
-}
{- Note [Satisfaction Condition Preservation across Signature Morphisms]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[tag:note-satisfaction-iso]
In Goguen-Burstall Institutions, the central axiom is the Satisfaction Condition:
for any signature morphism σ : Σ → Σ', sentence φ ∈ Sen(Σ), and model M' ∈ Mod(Σ'):
Mod(σ)(M') ⊨_Σ φ ⟺ M' ⊨_Σ' Sen(σ)(φ)
In classical model theory, this condition is a meta-theoretic biconditional (⟺) over {True, False}.
In Gargamelle, where satisfaction is enriched over the structured monoid 'Evidence', the biconditional
is reified as a computational isomorphism 'SatisfactionIso':
- 'forwardEvidence' translates evidence from the reduct model to the extended model.
- 'backwardEvidence' translates counterexample witnesses from the extended model back into
the vocabulary of the base institution.
This ensures that counterexamples discovered by SMT solvers or test runners in a refined
target system can be translated soundly back to the source specification.
-}
-- | Observable V-Enriched Satisfaction Evidence (replaces opaque Bool).
--
-- See Note [Free Verifier AST and Algebraic Counterexample Evidence] [ref:note-free-verifier-ast].
--
-- Preserves structural counterexamples so autonomous agents do not repeat failed patches.
data Evidence
= VerifiedSection
| Counterexample
{ violatedSymbol :: String
, witnessPayload :: String
}
deriving (Eq, Show)
-- | Evidence forms a Monoid where VerifiedSection is the identity and
-- Counterexamples accumulate across verification checks.
instance Semigroup Evidence where
VerifiedSection <> e = e
e <> VerifiedSection = e
Counterexample s1 w1 <> Counterexample s2 w2 =
Counterexample (s1 ++ "; " ++ s2) (w1 ++ " | " ++ w2)
instance Monoid Evidence where
mempty = VerifiedSection
-- | Observable Free Divisible/Decidable Verifier AST.
--
-- See Note [Free Verifier AST and Algebraic Counterexample Evidence] [ref:note-free-verifier-ast].
--
-- Every product split, sum branch, and atomic check is a first-class constructor
-- that an AI agent or SMT pipe can inspect, optimize, or translate before execution.
data Verifier (model :: Type) where
ConquerV :: Verifier a
LoseV :: ObsMor a Void -> Verifier a
AtomCheck :: String -> (model -> Evidence) -> Verifier model
ContramapV :: ObsMor a b -> Verifier b -> Verifier a
DivideV :: ObsMor a (b, c) -> Verifier b -> Verifier c -> Verifier a
ChooseV :: ObsMor a (Either b c) -> Verifier b -> Verifier c -> Verifier a
instance Contravariant Verifier where
contramap f = ContramapV (SymbolicStep "contramap" f)
instance Divisible Verifier where
conquer = ConquerV
divide split = DivideV (SymbolicStep "divide" split)
instance Decidable Verifier where
lose f = LoseV (SymbolicStep "lose" f)
choose split = ChooseV (SymbolicStep "choose" split)
-- | Helper to create an atomic predicate verifier returning a Counterexample upon failure.
verifyPredicate :: String -> (model -> Bool) -> Verifier model
verifyPredicate name p = AtomCheck name $ \m ->
if p m
then VerifiedSection
else Counterexample name ("Predicate violated: " ++ name)
-- | Execute the observable Verifier AST against a concrete runtime model.
evalVerifier :: Verifier model -> model -> Evidence
evalVerifier ConquerV _ = VerifiedSection
evalVerifier (LoseV f) m = absurd (evalObsMor f m)
evalVerifier (AtomCheck _ check) m = check m
evalVerifier (ContramapV f v) m = evalVerifier v (evalObsMor f m)
evalVerifier (DivideV split vB vC) m =
let (b, c) = evalObsMor split m
in evalVerifier vB b <> evalVerifier vC c
evalVerifier (ChooseV split vB vC) m =
either (evalVerifier vB) (evalVerifier vC) (evalObsMor split m)
-- | Static introspection: Extract all verification checks and morphism steps
-- embedded inside a Verifier without needing a runtime model.
inspectVerifierPlan :: Verifier model -> [String]
inspectVerifierPlan ConquerV = ["Conquer"]
inspectVerifierPlan (LoseV f) = "Lose" : inspectObsMor f
inspectVerifierPlan (AtomCheck sym _) = ["AtomCheck:" ++ sym]
inspectVerifierPlan (ContramapV f v) = inspectObsMor f ++ inspectVerifierPlan v
inspectVerifierPlan (DivideV f vB vC) = inspectObsMor f ++ inspectVerifierPlan vB ++ inspectVerifierPlan vC
inspectVerifierPlan (ChooseV f vB vC) = inspectObsMor f ++ inspectVerifierPlan vB ++ inspectVerifierPlan vC
-- | Observable Witness of the Satisfaction Condition Equivalence (⟺):
--
-- See Note [Satisfaction Condition Preservation across Signature Morphisms] [ref:note-satisfaction-iso].
--
-- Translates verification evidence forward and backward across a signature morphism.
data SatisfactionIso = SatisfactionIso
{ forwardEvidence :: ObsMor Evidence Evidence
, backwardEvidence :: ObsMor Evidence Evidence
}