[ new ] Introduce a Biinjective interface

This commit is contained in:
Denis Buzdalov 2022-05-19 22:32:22 +03:00 committed by G. Allais
parent a3542ad0cd
commit d3fa76052b
8 changed files with 87 additions and 16 deletions

View File

@ -1,5 +1,7 @@
module Control.Function module Control.Function
%default total
||| An injective function maps distinct elements to distinct elements. ||| An injective function maps distinct elements to distinct elements.
public export public export
interface Injective (f : a -> b) | f where interface Injective (f : a -> b) | f where
@ -16,7 +18,7 @@ inj _ eq = irrelevantEq (injective eq)
public export public export
[ComposeInjective] {f : a -> b} -> {g : b -> c} -> [ComposeInjective] {f : a -> b} -> {g : b -> c} ->
(Injective f, Injective g) => Injective (g . f) where (Injective f, Injective g) => Injective (g . f) where
injective prf = injective $ injective prf injective = injective . injective
||| If (g . f) is injective, so is f. ||| If (g . f) is injective, so is f.
public export public export
@ -27,3 +29,47 @@ public export
public export public export
[IdInjective] Injective Prelude.id where [IdInjective] Injective Prelude.id where
injective = id injective = id
----------------------------------------
||| An bi-injective function maps distinct elements to distinct elements in both arguments.
||| This is more strict than injectivity on each of arguments.
||| For instance, list appending is injective on both arguments but is not biinjective.
public export
interface Biinjective (f : a -> b -> c) | f where
constructor MkBiinjective
biinjective : {x, y : a} -> {v, w : b} -> f x v = f y w -> (x = y, v = w)
public export
biinj : (0 f : _) -> (0 _ : Biinjective f) => (0 _ : f x v = f y w) -> (x = y, v = w)
biinj _ eq = let 0 bii = biinjective eq in (irrelevantEq $ fst bii, irrelevantEq $ snd bii)
public export
[ComposeBiinjective] {f : a -> b -> c} -> {g : c -> d} ->
Biinjective f => Injective g => Biinjective (g .: f) where
biinjective = biinjective . injective
||| If (g .: f) is biinjective, so is f.
public export
[BiinjFromComp] {f : a -> b -> c} -> {g : c -> d} ->
Biinjective (g .: f) => Biinjective f where
biinjective = biinjective {f = (g .: f)} . cong g
public export
[FlipBiinjective] {f : a -> b -> c} ->
Biinjective f => Biinjective (flip f) where
biinjective = swap . biinjective
public export
[FromBiinjectiveL] {f : a -> b -> c} -> {x : a} ->
Biinjective f => Injective (f x) where
injective = snd . biinjective
public export
[FromBiinjectiveR] {f : a -> b -> c} -> {y : b} ->
Biinjective f => Injective (`f` y) where
injective = fst . biinjective
export
Biinjective MkPair where
biinjective Refl = (Refl, Refl)

View File

@ -1,5 +1,7 @@
module Data.List module Data.List
import public Control.Function
import Data.Nat import Data.Nat
import Data.List1 import Data.List1
import Data.Fin import Data.Fin
@ -914,6 +916,11 @@ export
||| (::) is injective ||| (::) is injective
export export
Biinjective Prelude.(::) where
biinjective Refl = (Refl, Refl)
||| Heterogeneous injectivity for (::)
export
consInjective : forall x, xs, y, ys . consInjective : forall x, xs, y, ys .
the (List a) (x :: xs) = the (List b) (y :: ys) -> (x = y, xs = ys) the (List a) (x :: xs) = the (List b) (y :: ys) -> (x = y, xs = ys)
consInjective Refl = (Refl, Refl) consInjective Refl = (Refl, Refl)

View File

@ -1,7 +1,7 @@
module Data.List1 module Data.List1
import public Data.Zippable import public Data.Zippable
import Control.Function import public Control.Function
%default total %default total

View File

@ -12,9 +12,14 @@ import Data.List1
%default total %default total
export export
-- %deprecate -- deprecated in favor of Biinjective interface
consInjective : (x ::: xs) === (y ::: ys) -> (x === y, xs === ys) consInjective : (x ::: xs) === (y ::: ys) -> (x === y, xs === ys)
consInjective Refl = (Refl, Refl) consInjective Refl = (Refl, Refl)
export
Biinjective (:::) where
biinjective Refl = (Refl, Refl)
export export
{x : a} -> Injective (x :::) where {x : a} -> Injective (x :::) where
injective Refl = Refl injective Refl = Refl
@ -64,6 +69,5 @@ fromListAppend [] ys with (fromList ys)
_ | (Just _) = Refl _ | (Just _) = Refl
fromListAppend (x::xs) ys with (fromList ys) proof prf fromListAppend (x::xs) ys with (fromList ys) proof prf
fromListAppend (x::xs) [] | Nothing = rewrite appendNilRightNeutral xs in Refl fromListAppend (x::xs) [] | Nothing = rewrite appendNilRightNeutral xs in Refl
fromListAppend (x::xs) (y::ys) | (Just $ l:::ls) = do fromListAppend (x::xs) (y::ys) | (Just $ l:::ls) =
let (prfL, prfLs) = consInjective $ injective prf let (Refl, Refl) = biinjective $ injective prf in Refl
rewrite prfL; rewrite prfLs; Refl

View File

@ -51,6 +51,10 @@ export
{y : _} -> Injective (`Both` y) where {y : _} -> Injective (`Both` y) where
injective Refl = Refl injective Refl = Refl
export
Biinjective Both where
biinjective Refl = (Refl, Refl)
public export public export
(Show a, Show b) => Show (These a b) where (Show a, Show b) => Show (These a b) where
showPrec d (This x) = showCon d "This" $ showArg x showPrec d (This x) = showCon d "This" $ showArg x

View File

@ -33,10 +33,6 @@ lengthCorrect : (xs : Vect len elem) -> length xs = len
lengthCorrect [] = Refl lengthCorrect [] = Refl
lengthCorrect (_ :: xs) = rewrite lengthCorrect xs in Refl lengthCorrect (_ :: xs) = rewrite lengthCorrect xs in Refl
||| If two vectors are equal, their heads and tails are equal
vectInjective : {0 xs : Vect n a} -> {0 ys : Vect m b} -> x::xs = y::ys -> (x = y, xs = ys)
vectInjective Refl = (Refl, Refl)
export export
{x : a} -> Injective (Vect.(::) x) where {x : a} -> Injective (Vect.(::) x) where
injective Refl = Refl injective Refl = Refl
@ -45,6 +41,10 @@ export
{xs : Vect n a} -> Injective (\x => Vect.(::) x xs) where {xs : Vect n a} -> Injective (\x => Vect.(::) x xs) where
injective Refl = Refl injective Refl = Refl
export
Biinjective Vect.(::) where
biinjective Refl = (Refl, Refl)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Indexing into vectors -- Indexing into vectors
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -333,8 +333,8 @@ DecEq a => DecEq (Vect n a) where
decEq [] [] = Yes Refl decEq [] [] = Yes Refl
decEq (x::xs) (y::ys) with (decEq x y, decEq xs ys) decEq (x::xs) (y::ys) with (decEq x y, decEq xs ys)
decEq (x::xs) (x::xs) | (Yes Refl, Yes Refl) = Yes Refl decEq (x::xs) (x::xs) | (Yes Refl, Yes Refl) = Yes Refl
decEq (x::xs) (y::ys) | (No nhd, _) = No $ nhd . fst . vectInjective decEq (x::xs) (y::ys) | (No nhd, _) = No $ nhd . fst . biinjective
decEq (x::xs) (y::ys) | (_, No ntl) = No $ ntl . snd . vectInjective decEq (x::xs) (y::ys) | (_, No ntl) = No $ ntl . snd . biinjective
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Order -- Order

View File

@ -1,5 +1,7 @@
module Data.List.Equalities module Data.List.Equalities
import Control.Function
import Data.List import Data.List
%default total %default total
@ -34,7 +36,7 @@ snocInjective {xs = z :: xs} {ys = []} prf =
let snocIsNil = snd $ consInjective {x = z} {xs = xs ++ [x]} {ys = []} prf let snocIsNil = snd $ consInjective {x = z} {xs = xs ++ [x]} {ys = []} prf
in void $ snocNonEmpty snocIsNil in void $ snocNonEmpty snocIsNil
snocInjective {xs = w :: xs} {ys = z :: ys} prf = snocInjective {xs = w :: xs} {ys = z :: ys} prf =
let (wEqualsZ, xsSnocXEqualsYsSnocY) = consInjective prf let (wEqualsZ, xsSnocXEqualsYsSnocY) = biinjective prf
(xsEqualsYS, xEqualsY) = snocInjective xsSnocXEqualsYsSnocY (xsEqualsYS, xEqualsY) = snocInjective xsSnocXEqualsYsSnocY
in (consCong2 wEqualsZ xsEqualsYS, xEqualsY) in (consCong2 wEqualsZ xsEqualsYS, xEqualsY)
@ -80,7 +82,7 @@ lengthSnoc x (_ :: xs) = cong S (lengthSnoc x xs)
export export
appendSameLeftInjective : (xs, ys, zs : List a) -> zs ++ xs = zs ++ ys -> xs = ys appendSameLeftInjective : (xs, ys, zs : List a) -> zs ++ xs = zs ++ ys -> xs = ys
appendSameLeftInjective xs ys [] = id appendSameLeftInjective xs ys [] = id
appendSameLeftInjective xs ys (_::zs) = appendSameLeftInjective xs ys zs . snd . consInjective appendSameLeftInjective xs ys (_::zs) = appendSameLeftInjective xs ys zs . snd . biinjective
||| Appending the same list at right is injective. ||| Appending the same list at right is injective.
export export
@ -92,16 +94,24 @@ appendSameRightInjective xs ys (z::zs) = rewrite appendAssociative xs [z] zs in
rewrite appendAssociative ys [z] zs in rewrite appendAssociative ys [z] zs in
fst . snocInjective . appendSameRightInjective (xs ++ [z]) (ys ++ [z]) zs fst . snocInjective . appendSameRightInjective (xs ++ [z]) (ys ++ [z]) zs
export
{zs : List a} -> Injective (zs ++) where
injective = appendSameLeftInjective _ _ zs
export
{zs : List a} -> Injective (++ zs) where
injective = appendSameRightInjective _ _ zs
||| List cannot be equal to itself prepended with some non-empty list. ||| List cannot be equal to itself prepended with some non-empty list.
export export
appendNonEmptyLeftNotEq : (zs, xs : List a) -> NonEmpty xs => Not (zs = xs ++ zs) appendNonEmptyLeftNotEq : (zs, xs : List a) -> NonEmpty xs => Not (zs = xs ++ zs)
appendNonEmptyLeftNotEq [] (_::_) Refl impossible appendNonEmptyLeftNotEq [] (_::_) Refl impossible
appendNonEmptyLeftNotEq (z::zs) (_::xs) prf appendNonEmptyLeftNotEq (z::zs) (_::xs) prf
= appendNonEmptyLeftNotEq zs (xs ++ [z]) @{SnocNonEmpty xs z} = appendNonEmptyLeftNotEq zs (xs ++ [z]) @{SnocNonEmpty xs z}
$ rewrite sym $ appendAssociative xs [z] zs in snd $ consInjective prf $ rewrite sym $ appendAssociative xs [z] zs in snd $ biinjective prf
||| List cannot be equal to itself appended with some non-empty list. ||| List cannot be equal to itself appended with some non-empty list.
export export
appendNonEmptyRightNotEq : (zs, xs : List a) -> NonEmpty xs => Not (zs = zs ++ xs) appendNonEmptyRightNotEq : (zs, xs : List a) -> NonEmpty xs => Not (zs = zs ++ xs)
appendNonEmptyRightNotEq [] (_::_) Refl impossible appendNonEmptyRightNotEq [] (_::_) Refl impossible
appendNonEmptyRightNotEq (_::zs) (x::xs) prf = appendNonEmptyRightNotEq zs (x::xs) $ snd $ consInjective prf appendNonEmptyRightNotEq (_::zs) (x::xs) prf = appendNonEmptyRightNotEq zs (x::xs) $ snd $ biinjective prf

View File

@ -39,7 +39,7 @@ reversePalindromeEqualsLemma x x' xs prf = equateInnerAndOuter flipHeadX
flipLastX' : reverse (xs ++ [x']) = x :: xs -> (x' :: reverse xs) = (x :: xs) flipLastX' : reverse (xs ++ [x']) = x :: xs -> (x' :: reverse xs) = (x :: xs)
flipLastX' prf = rewrite (revAppend xs [x']) in prf flipLastX' prf = rewrite (revAppend xs [x']) in prf
cancelOuter : (reverse (xs ++ [x'])) = x :: xs -> reverse xs = xs cancelOuter : (reverse (xs ++ [x'])) = x :: xs -> reverse xs = xs
cancelOuter prf = snd (consInjective (flipLastX' prf)) cancelOuter prf = snd (biinjective (flipLastX' prf))
equateInnerAndOuter equateInnerAndOuter
: reverse (xs ++ [x']) ++ [x] = (x :: xs) ++ [x'] : reverse (xs ++ [x']) ++ [x] = (x :: xs) ++ [x']
-> (reverse xs = xs, x = x') -> (reverse xs = xs, x = x')