Source code on Github
{-# OPTIONS --without-K --safe #-}
module Tactic.Solver.Ring.Core where
open import Algebra using (CommutativeSemiring; CommutativeRing)
open import Data.Bool using (Bool; true; false; if_then_else_)
open import Data.Integer using (ℤ; +_; -[1+_])
open import Data.List as List using (List; _∷_; [])
open import Data.Maybe as Maybe using (Maybe; just; nothing; maybe)
open import Data.Nat using (ℕ; suc; zero)
open import Data.Nat.Reflection using (toTerm)
open import Data.Product using (_,_; _×_)
open import Data.Unit
open import Data.Vec as Vec using (Vec)
open import Function
open import Class.Functor
open import Class.Monad.Instances
open import Reflection
open import Reflection.AST.Argument
import Reflection.AST.Name as Name
open import Reflection.AST.Term
open import Reflection.TCM.Syntax hiding (_<$>_)
open import Reflection.Utils.Args using (vArgs)
open import Reflection.Utils.Core using (extractNat)
open import Reflection.Utils.Records
using (fieldProjection; projectField)
open import Tactic.Solver.Algebra
import Tactic.Solver.Ring.IntegerCoefficients as IntC
module NatC {c ℓ} (R : CommutativeSemiring c ℓ) where
open import Algebra.Solver.Ring.NaturalCoefficients.Default R public
conP : ∀ {n} → ℕ → Polynomial n
conP = con
private
data RingSide : Set where
csr cr : RingSide
bundleTypeOf : RingSide → Term
bundleTypeOf csr = def (quote CommutativeSemiring) (2 ⋯⟨∷⟩ [])
bundleTypeOf cr = def (quote CommutativeRing) (2 ⋯⟨∷⟩ [])
conName addName mulName eqName solveName reflName zeroName oneName : RingSide → Name
conName csr = quote NatC.conP ; conName cr = quote IntC.conP
addName csr = quote NatC._:+_ ; addName cr = quote IntC._:+_
mulName csr = quote NatC._:*_ ; mulName cr = quote IntC._:*_
eqName csr = quote NatC._:=_ ; eqName cr = quote IntC._:=_
solveName csr = quote NatC.solve ; solveName cr = quote IntC.solve
zeroName csr = quote CommutativeSemiring.0# ; zeroName cr = quote CommutativeRing.0#
oneName csr = quote CommutativeSemiring.1# ; oneName cr = quote CommutativeRing.1#
reflName csr = quote CommutativeSemiring.refl ; reflName cr = quote CommutativeRing.refl
private
defP : EncodeEnv → Name → List Term → Term
defP env nm args =
def nm (2 ⋯⟅∷⟆ EncodeEnv.R↓↓ env ⟨∷⟩ toTerm (EncodeEnv.numAtoms env) ⟅∷⟆ List.map vArg args)
opEnc : ∀ {n} → Name → EncodeEnv → Vec Term n → Term
opEnc nm env args = defP env nm (Vec.toList args)
natLitTerm : RingSide → ℕ → Term
natLitTerm csr n = toTerm n
natLitTerm cr n = con (quote +_) (toTerm n ⟨∷⟩ [])
constEnc : RingSide → ℕ → EncodeEnv → Term
constEnc s n env = defP env (conName s) (natLitTerm s n ∷ [])
private
csrSlots : List Slot
csrSlots =
mkSlot (quote CommutativeSemiring._+_) 2 op (opEnc (addName csr))
∷ mkSlot (quote CommutativeSemiring._*_) 2 op (opEnc (mulName csr))
∷ mkSlot (zeroName csr) 0 op (λ env _ → constEnc csr 0 env)
∷ mkSlot (oneName csr) 0 op (λ env _ → constEnc csr 1 env)
∷ []
crSlots : List Slot
crSlots =
mkSlot (quote CommutativeRing._+_) 2 op (opEnc (addName cr))
∷ mkSlot (quote CommutativeRing._*_) 2 op (opEnc (mulName cr))
∷ mkSlot (quote CommutativeRing._-_) 2 derived (opEnc (quote IntC._:-_))
∷ mkSlot (quote (CommutativeRing.-_)) 1 op (opEnc (quote IntC.negP))
∷ mkSlot (zeroName cr) 0 op (λ env _ → constEnc cr 0 env)
∷ mkSlot (oneName cr) 0 op (λ env _ → constEnc cr 1 env)
∷ []
slotsFor : RingSide → List Slot
slotsFor csr = csrSlots
slotsFor cr = crSlots
private
data LitStyle : Set where
natStyle : LitStyle
wrapped : Name → LitStyle
detectLitStyle : Term → Term → Maybe LitStyle
detectLitStyle (con cz argsZ) (con co argsO) =
case (cz Name.≡ᵇ co) of λ where
true → case (vArgs argsZ , vArgs argsO) of λ where
((z₀ ∷ []) , (o₀ ∷ [])) → case (extractNat z₀ , extractNat o₀) of λ where
(just 0 , just 1) → just (wrapped cz)
_ → fallthrough
_ → fallthrough
false → fallthrough
where
fallthrough : Maybe LitStyle
fallthrough = case (extractNat (con cz argsZ) , extractNat (con co argsO)) of λ where
(just 0 , just 1) → just natStyle
_ → nothing
detectLitStyle z o = case (extractNat z , extractNat o) of λ where
(just 0 , just 1) → just natStyle
_ → nothing
mkLiteralSpec : RingSide → Maybe LitStyle → Maybe LiteralSpec
mkLiteralSpec _ nothing = nothing
mkLiteralSpec s (just style) = just (record
{ litCon = litConOf style
; negLitCon = negConOf s style
; peelSuc = isNat style
; peelWrappedSuc = isPos style
; encodeNat = λ env n → constEnc s n env
; encodeNegSuc = λ env n → defP env (conName s) (con (quote -[1+_]) (toTerm n ⟨∷⟩ []) ∷ [])
; encodeSucPeel = λ env t → defP env (addName s) (constEnc s 1 env ∷ t ∷ [])
})
where
litConOf : LitStyle → Maybe Name
litConOf natStyle = nothing
litConOf (wrapped C) = just C
isNat : LitStyle → Bool
isNat natStyle = true
isNat _ = false
isPos : LitStyle → Bool
isPos (wrapped C) = C Name.≡ᵇ quote +_
isPos _ = false
negConOf : RingSide → LitStyle → Maybe Name
negConOf cr (wrapped C) = if C Name.≡ᵇ quote +_ then just (quote -[1+_]) else nothing
negConOf _ _ = nothing
private
detectFor : RingSide → Term → TC DetectedTheory
detectFor side R = do
slotted ← resolveSlots numParams (slotsFor side) R
ls ← litStyleOf slotted
pure (record
{ operators = operatorsOf slotted
; literalSpec = mkLiteralSpec side ls
; blockedNames = blockedOf slotted
; encodeEq = λ env x y → defP env (eqName side) (x ∷ y ∷ [])
; finishSolve = finish
})
where
numParams : ℕ
numParams = 2
litStyleOf : List (Slot × Term) → TC (Maybe LitStyle)
litStyleOf slotted =
case (lookupSlot (zeroName side) slotted , lookupSlot (oneName side) slotted) of λ where
(just z , just o) → do
z' ← reduce z
o' ← reduce o
pure (detectLitStyle z' o')
_ → pure nothing
finish : EncodeEnv → Term → List Term → Term
finish env body atoms =
def (solveName side)
(2 ⋯⟅∷⟆ R↓ ⟨∷⟩ toTerm (EncodeEnv.numAtoms env) ⟨∷⟩ body ⟨∷⟩ `refl ⟨∷⟩ List.map vArg atoms)
where
R↓ = EncodeEnv.R↓ env
`refl = def (reflName side) (2 ⋯⟅∷⟆ R↓ ⟨∷⟩ 1 ⋯⟅∷⟆ [])
private
ringTheory : RingSide → Theory
ringTheory s = record
{ macroName = "solve-≈"
; detect = detectFor s
}
detectSide : Term → TC (RingSide × Term)
detectSide R =
((cr ,_) <$> checkType R (bundleTypeOf cr))
<|> ((csr ,_) <$> checkType R (bundleTypeOf csr))
<|> typeError
( strErr "solve-≈: the bundle argument must be a "
∷ strErr "`CommutativeSemiring` or a `CommutativeRing`, but "
∷ termErr R
∷ strErr " is neither."
∷ [])
solve-≈-macro : Term → Term → TC ⊤
solve-≈-macro R hole = do
side , R' ← detectSide R
commitTC
solveByTheory (ringTheory side) R' hole
macro
solve-≈ : Term → Term → TC ⊤
solve-≈ = solve-≈-macro