{-# OPTIONS --safe --without-K --no-exact-split #-} module Tactic.Homomorphism.Group where open import Algebra.Morphism open import Algebra.Bundles using (Group) open import Function open import Level open import Data.Bool as Bool using (Bool; _∨_; if_then_else_) open import Data.Maybe as Maybe using (Maybe; just; nothing; maybe) open import Data.List as List using (List; _∷_; []) open import Data.Nat as ℕ using (ℕ; suc; zero) open import Data.Product as Product using (_×_; _,_) open import Agda.Builtin.Reflection open import Reflection.TypeChecking.MonadSyntax open import Reflection.Argument import Relation.Binary.Reasoning.Setoid as SetoidReasoning open import Algebra.Morphism.Group infixl 7 _∙'_ data Expr {a} (A : Set a) : Set a where _∙'_ : Expr A → Expr A → Expr A ε' : Expr A inv' : Expr A → Expr A [_↑] : A → Expr A module _ {c₁ ℓ₁ c₂ ℓ₂} {From : Group c₁ ℓ₁} {To : Group c₂ ℓ₂} (f : GroupMorphism From To) where open Group From renaming (_∙_ to _∙₁_; ε to ε₁; Carrier to Carrier₁; _⁻¹ to _⁻¹₁; _≈_ to _≈₁_; inverseˡ to inverseˡ₁) open Group To renaming (_∙_ to _∙₂_; ε to ε₂; Carrier to Carrier₂; _⁻¹ to _⁻¹₂; _≈_ to _≈₂_; setoid to setoid₂; ∙-cong to ∙-cong₂; ∙-congʳ to ∙-congʳ₂; ∙-congˡ to ∙-congˡ₂; identityˡ to identityˡ₂; identityʳ to identityʳ₂; inverseʳ to inverseʳ₂; assoc to assoc₂; ⁻¹-cong to ⁻¹-cong₂) open GroupMorphism f open SetoidReasoning setoid₂ [_↓] : Expr Carrier₁ → Carrier₁ [ x ∙' y ↓] = [ x ↓] ∙₁ [ y ↓] [ ε' ↓] = ε₁ [ inv' x ↓] = [ x ↓] ⁻¹₁ [ [ x ↑] ↓] = x f[_↓] : Expr Carrier₁ → Carrier₂ f[ e ↓] = morphism [ e ↓] f[_⇓] : Expr Carrier₁ → Carrier₂ f[ x ∙' y ⇓] = f[ x ⇓] ∙₂ f[ y ⇓] f[ ε' ⇓] = ε₂ f[ inv' x ⇓] = f[ x ⇓] ⁻¹₂ f[ [ x ↑] ⇓] = morphism x proof : (e : Expr Carrier₁) → f[ e ↓] ≈₂ f[ e ⇓] proof (x ∙' y) = begin f[ x ∙' y ↓] ≡⟨⟩ morphism ([ x ↓] ∙₁ [ y ↓]) ≈⟨ ∙-homo [ x ↓] [ y ↓] ⟩ morphism [ x ↓] ∙₂ morphism [ y ↓] ≡⟨⟩ f[ x ↓] ∙₂ f[ y ↓] ≈⟨ ∙-cong₂ (proof x) (proof y) ⟩ f[ x ⇓] ∙₂ f[ y ⇓] ≡⟨⟩ f[ x ∙' y ⇓] ∎ proof ε' = ε-homo proof (inv' x) = begin f[ inv' x ↓] ≈˘⟨ identityʳ₂ f[ inv' x ↓] ⟩ f[ inv' x ↓] ∙₂ ε₂ ≈˘⟨ ∙-congˡ₂ $ inverseʳ₂ f[ x ↓] ⟩ f[ inv' x ↓] ∙₂ (f[ x ↓] ∙₂ f[ x ↓] ⁻¹₂) ≈˘⟨ assoc₂ f[ inv' x ↓] f[ x ↓] (f[ x ↓] T.⁻¹) ⟩ (f[ inv' x ↓] ∙₂ f[ x ↓]) ∙₂ f[ x ↓] ⁻¹₂ ≈˘⟨ ∙-congʳ₂ $ ∙-homo [ inv' x ↓] [ x ↓] ⟩ morphism ([ inv' x ↓] ∙₁ [ x ↓]) ∙₂ f[ x ↓] ⁻¹₂ ≈⟨ ∙-congʳ₂ $ ⟦⟧-cong $ inverseˡ₁ [ x ↓] ⟩ morphism ε₁ ∙₂ f[ x ↓] ⁻¹₂ ≈⟨ ∙-congʳ₂ $ ε-homo ⟩ ε₂ ∙₂ f[ x ↓] ⁻¹₂ ≈⟨ identityˡ₂ (f[ x ↓] T.⁻¹) ⟩ f[ x ↓] ⁻¹₂ ≈⟨ ⁻¹-cong₂ $ proof x ⟩ f[ x ⇓] ⁻¹₂ ≡⟨⟩ f[ inv' x ⇓] ∎ proof [ x ↑] = begin f[ [ x ↑] ↓] ∎ _==_ = primQNameEquality {-# INLINE _==_ #-} is-∙ : Name → Bool is-∙ n = n == (quote Group._∙_) is-ε : Name → Bool is-ε n = n == (quote Group.ε) is-⁻¹ : Name → Bool is-⁻¹ n = n == (quote Group._⁻¹) mutual ″∙″ : List (Arg Term) → Term ″∙″ (x ⟨∷⟩ y ⟨∷⟩ []) = quote _∙'_ ⟨ con ⟩ buildExpr x ⟨∷⟩ buildExpr y ⟨∷⟩ [] ″∙″ (x ∷ xs) = ″∙″ xs ″∙″ _ = unknown ″⁻¹″ : List (Arg Term) → Term ″⁻¹″ (x ⟨∷⟩ []) = quote inv' ⟨ con ⟩ buildExpr x ⟨∷⟩ [] ″⁻¹″ (x ∷ xs) = ″⁻¹″ xs ″⁻¹″ _ = unknown ″ε″ : Term ″ε″ = quote ε' ⟨ con ⟩ [] [_↑]' : Term → Term [ t ↑]' = quote [_↑] ⟨ con ⟩ (t ⟨∷⟩ []) buildExpr : Term → Term buildExpr t@(def n xs) = if is-∙ n then ″∙″ xs else if is-⁻¹ n then ″⁻¹″ xs else if is-ε n then ″ε″ else [ t ↑]' buildExpr t@(con n xs) = if is-∙ n then ″∙″ xs else if is-⁻¹ n then ″⁻¹″ xs else if is-ε n then ″ε″ else [ t ↑]' buildExpr t = quote [_↑] ⟨ con ⟩ (t ⟨∷⟩ []) getArgs : Term → Maybe (Term × Term) getArgs (def _ xs) = go xs where go : List (Arg Term) → Maybe (Term × Term) go (vArg x ∷ vArg y ∷ []) = just (x , y) go (x ∷ xs) = go xs go _ = nothing getArgs _ = nothing constructSoln : Term → Term → Term → Term → Term constructSoln f eq lhs rhs = let grp = quote GroupMorphism.to-group ⟨ def ⟩ f ⟨∷⟩ [] in quote Group.trans ⟨ def ⟩ grp ⟨∷⟩ (quote Group.trans ⟨ def ⟩ grp ⟨∷⟩ (quote Group.sym ⟨ def ⟩ grp ⟨∷⟩ (quote proof ⟨ def ⟩ f ⟨∷⟩ buildExpr lhs ⟨∷⟩ []) ⟨∷⟩ []) ⟨∷⟩ (quote GroupMorphism.⟦⟧-cong ⟨ def ⟩ f ⟨∷⟩ eq ⟨∷⟩ []) ⟨∷⟩ [] ) ⟨∷⟩ (quote proof ⟨ def ⟩ f ⟨∷⟩ buildExpr rhs ⟨∷⟩ []) ⟨∷⟩ [] constructReturn : Term → Term → Term → Term constructReturn f lhs rhs = let grp = quote GroupMorphism.to-group ⟨ def ⟩ f ⟨∷⟩ [] in let lhs' = quote f[_⇓] ⟨ def ⟩ f ⟨∷⟩ buildExpr lhs ⟨∷⟩ [] in let rhs' = quote f[_⇓] ⟨ def ⟩ f ⟨∷⟩ buildExpr rhs ⟨∷⟩ [] in quote Group._≈_ ⟨ def ⟩ grp ⟨∷⟩ lhs' ⟨∷⟩ rhs' ⟨∷⟩ [] solve-macro : Term → Term → Term → TC _ solve-macro f eq hole = do eq' ← inferType eq >>= normalise just (lhs , rhs) ← returnTC (getArgs eq') where nothing → typeError (strErr "could not split arg" ∷ termErr eq ∷ []) let soln = constructSoln f eq lhs rhs returnType ← normalise $ constructReturn f lhs rhs hole' ← checkType hole returnType unify hole' soln macro ⟨_⟩⦅_⦆ : Term → Term → Term → TC _ ⟨_⟩⦅_⦆ = solve-macro