{-# OPTIONS --without-K --safe #-}
module Tactic.RingSolver where
open import Agda.Builtin.Reflection
open import Algebra
open import Data.Fin as Fin using (Fin)
open import Data.Vec as Vec using (Vec; _∷_; [])
open import Data.List as List using (List; _∷_; [])
open import Data.Maybe.Base as Maybe using (Maybe; just; nothing; fromMaybe)
open import Data.Nat using (ℕ; suc; zero; _<ᵇ_)
open import Data.Nat.Reflection using (toTerm; toFinTerm)
open import Data.Bool using (Bool; if_then_else_; true; false)
open import Data.Unit using (⊤)
open import Data.String using (String)
open import Data.Product using (_,_)
open import Function
open import Reflection.Argument
open import Reflection.Term
open import Reflection.TypeChecking.Monad.Syntax
open import Tactic.RingSolver.NonReflective renaming (solve to solve-fn)
open import Tactic.RingSolver.Core.AlmostCommutativeRing
open import Tactic.RingSolver.Core.NatSet as NatSet
open import Tactic.RingSolver.Core.ReflectionHelp
open AlmostCommutativeRing
private
record RingNames : Set where
constructor +⇒_*⇒_^⇒_-⇒_
field
+′ *′ ^′ -′ : Maybe Name
checkIsRing : Term → TC Term
checkIsRing ring = checkType ring (def (quote AlmostCommutativeRing) (2 ⋯⟨∷⟩ []))
getVariableIDs : Term → Maybe NatSet
getVariableIDs = go []
where
go : NatSet → Term → Maybe NatSet
go t (con (quote List._∷_) (_ ∷ _ ∷ var i [] ⟨∷⟩ xs ⟨∷⟩ _)) = go (insert i t) xs
go t (con (quote List.List.[]) _) = just t
go _ _ = nothing
module OverRing (ring : Term) where
infixr 6 _$ʳ_
_$ʳ_ : Name → Args Term → Term
nm $ʳ args = def nm (2 ⋯⟅∷⟆ ring ⟨∷⟩ args)
checkIsListOfVariables : Term → TC Term
checkIsListOfVariables xs =
checkType xs (def (quote List) (1 ⋯⟅∷⟆ (quote Carrier $ʳ []) ⟨∷⟩ [])) >>= normalise
getFieldName : Name → TC (Maybe Name)
getFieldName nm = normalise (nm $ʳ []) <&> λ where
(def f args) → just f
_ → nothing
getRingOperatorNames : TC RingNames
getRingOperatorNames = ⦇
+⇒ getFieldName (quote _+_)
*⇒ getFieldName (quote _*_)
^⇒ getFieldName (quote _^_)
-⇒ getFieldName (quote -_)
⦈
module _ (nms : RingNames) (numVars : ℕ) where
open RingNames nms
infix -1 _$ᵉ_
_$ᵉ_ : Name → List (Arg Term) → Term
e $ᵉ xs = con e (1 ⋯⟅∷⟆ quote Carrier $ʳ [] ⟅∷⟆ toTerm numVars ⟅∷⟆ xs)
Κ′ : Term → Term
Κ′ x = quote Κ $ᵉ (x ⟨∷⟩ [])
infix 4 _⇓≟_
_⇓≟_ : Maybe Name → Name → Bool
nothing ⇓≟ _ = false
just x ⇓≟ y = primQNameEquality x y
{-# INLINE _⇓≟_ #-}
module ToExpr (Ι′ : ℕ → Maybe Term) where
mutual
E⟨_⟩₂ : Name → List (Arg Term) → Term
E⟨ nm ⟩₂ (x ⟨∷⟩ y ⟨∷⟩ []) = nm $ᵉ (E x ⟨∷⟩ E y ⟨∷⟩ [])
E⟨ nm ⟩₂ (x ∷ xs) = E⟨ nm ⟩₂ xs
E⟨ nm ⟩₂ _ = unknown
E⟨_⟩₁ : Name → List (Arg Term) → Term
E⟨ nm ⟩₁ (x ⟨∷⟩ []) = nm $ᵉ (E x ⟨∷⟩ [])
E⟨ nm ⟩₁ (x ∷ xs) = E⟨ nm ⟩₁ xs
E⟨ _ ⟩₁ _ = unknown
E⟨^⟩ : List (Arg Term) → Term
E⟨^⟩ (x ⟨∷⟩ y ⟨∷⟩ []) = quote _⊛_ $ᵉ (E x ⟨∷⟩ y ⟨∷⟩ [])
E⟨^⟩ (x ∷ xs) = E⟨^⟩ xs
E⟨^⟩ _ = unknown
E : Term → Term
E (def (quote _+_) xs) = E⟨ quote _⊕_ ⟩₂ xs
E (def (quote _*_) xs) = E⟨ quote _⊗_ ⟩₂ xs
E (def (quote _^_) xs) = E⟨^⟩ xs
E (def (quote -_) xs) = E⟨ quote ⊝_ ⟩₁ xs
E (def nm xs) = if +′ ⇓≟ nm then E⟨ quote _⊕_ ⟩₂ xs else
if *′ ⇓≟ nm then E⟨ quote _⊗_ ⟩₂ xs else
if ^′ ⇓≟ nm then E⟨^⟩ xs else
if -′ ⇓≟ nm then E⟨ quote ⊝_ ⟩₁ xs else
Κ′ (def nm xs)
E v@(var x _) = fromMaybe (Κ′ v) (Ι′ x)
E (con (quote ℕ.suc) (x ⟨∷⟩ [])) = quote _⊕_ $ᵉ (Κ′ (toTerm 1) ⟨∷⟩ E x ⟨∷⟩ [])
E t = Κ′ t
callSolver : Vec String numVars → Term → Term → Args Type
callSolver nms lhs rhs =
2 ⋯⟅∷⟆ ring ⟨∷⟩ toTerm numVars ⟨∷⟩
vlams nms (quote _⊜_ $ʳ (toTerm numVars ⟅∷⟆ E lhs ⟨∷⟩ E rhs ⟨∷⟩ [])) ⟨∷⟩
hlams nms (quote refl $ʳ (1 ⋯⟅∷⟆ [])) ⟨∷⟩
[]
where
Ι′ : ℕ → Maybe Term
Ι′ i = if i <ᵇ numVars then just (var i []) else nothing
open ToExpr Ι′
constructSoln : NatSet → Term → Term → Term
constructSoln t lhs rhs =
quote trans $ʳ (3 ⋯⟅∷⟆
quote sym $ʳ (2 ⋯⟅∷⟆
quote Ops.correct $ʳ (1 ⋯⟅∷⟆ E lhs ⟨∷⟩ ρ ⟨∷⟩ []) ⟨∷⟩ [])
⟨∷⟩
(quote Ops.correct $ʳ (1 ⋯⟅∷⟆ E rhs ⟨∷⟩ ρ ⟨∷⟩ [])) ⟨∷⟩
[])
where
Ι′ : ℕ → Maybe Term
Ι′ i = Maybe.map (λ x → quote Ι $ᵉ (toFinTerm x ⟨∷⟩ [])) (lookup i t)
open ToExpr Ι′
ρ : Term
ρ = curriedTerm t
solve-∀-macro : Name → Term → TC ⊤
solve-∀-macro ring hole = do
ring′ ← checkIsRing (def ring [])
commitTC
let open OverRing ring′
operatorNames ← getRingOperatorNames
hole′ ← inferType hole >>= reduce
let variables , k , equation = underPi hole′
just (lhs ∷ rhs ∷ []) ← pure (getArgs 2 equation)
where nothing → typeError (strErr "Malformed call to solve." ∷
strErr "Expected target type to be like: ∀ x y → x + y ≈ y + x." ∷
strErr "Instead: " ∷
termErr hole′ ∷
[])
unify hole (def (quote solve-fn) (callSolver operatorNames variables k lhs rhs))
macro
solve-∀ : Name → Term → TC ⊤
solve-∀ = solve-∀-macro
solve-macro : Term → Name → Term → TC ⊤
solve-macro i ring hole = do
ring′ ← checkIsRing (def ring [])
commitTC
let open OverRing ring′
operatorNames ← getRingOperatorNames
listOfVariables′ ← checkIsListOfVariables i
commitTC
hole′ ← inferType hole >>= reduce
just vars′ ← pure (getVariableIDs listOfVariables′)
where nothing → typeError (strErr "Malformed call to solve." ∷
strErr "First argument should be a list of free variables." ∷
strErr "Instead: " ∷
termErr listOfVariables′ ∷
[])
just (lhs ∷ rhs ∷ []) ← pure (getArgs 2 hole′)
where nothing → typeError (strErr "Malformed call to solve." ∷
strErr "First argument should be a list of free variables." ∷
strErr "Instead: " ∷
termErr hole′ ∷
[])
unify hole (constructSoln operatorNames (List.length vars′) vars′ lhs rhs)
macro
solve : Term → Name → Term → TC ⊤
solve = solve-macro