Застрял на доказательстве с неоднородным равенством

У меня есть представление двоичного числа, плюс некоторое преобразование в Nat и обратно:

open import Data.Nat
open import Data.Nat.Properties
open import Function
open import Relation.Binary.PropositionalEquality hiding (trans; cong; subst; sym)
open import Relation.Binary.HeterogeneousEquality
open import Data.Unit
open import Algebra
module CS = CommutativeSemiring commutativeSemiring 

data Bin : ℕ → Set where
  zero  : Bin zero
  2*n   : ∀ {n} → Bin n → Bin (n + n)
  2*n+1 : ∀ {n} → Bin n → Bin (suc (n + n))

suc-lem : ∀ n → suc (suc (n + n)) ≡ suc n + suc n
suc-lem zero = refl
suc-lem (suc n) rewrite 
    CS.+-comm n (suc n)
  | suc-lem n | CS.+-comm n (suc (suc n)) 
  | CS.+-comm n (suc n) = refl

inc : ∀ {n} → Bin n → Bin (suc n)
inc zero = 2*n+1 zero
inc (2*n b) = 2*n+1 b
inc (2*n+1 {n} b) rewrite suc-lem n = 2*n (inc b)

nat2bin : (n : ℕ) → Bin n
nat2bin zero = zero
nat2bin (suc n) = inc (nat2bin n)

bin2nat : ∀ {n} → Bin n → ℕ
bin2nat {n} b = n

Я думаю, что для доказательства здесь мне нужно неоднородное равенство, поскольку обычно не очевидно, что индексы Nat двух Bin-ов равны. Однако я довольно неопытен в Agda, поэтому, пожалуйста, скажите мне, если подход неправильный.

Я застрял со следующим:

lem : ∀ n → 2*n+1 (inc (nat2bin n)) ≅ inc (inc (2*n+1 (nat2bin n)))
lem zero = refl
lem (suc n) = 
  subst
    (λ b → 2*n+1 (inc (inc (nat2bin n))) ≅ inc (inc b))
    (sym $ lem ?) ? 

Самым очевидным было бы подключить n к sym $ lem ?, но это приводит к ошибке с жалобой на suc (n + n) != n + suc n.

Я хотел бы знать, почему это происходит и чем можно помочь.


person András Kovács    schedule 10.06.2014    source источник
comment
Меня интересует использование типа данных Bin, а не Data.Bin.Bin из стандартной библиотеки. Также почему он позволяет бесконечно много представлений zero? Может хочешь 2*n : ∀ {n} → Bin (suc n) → Bin (suc n + suc n)?   -  person Helmut Grohne    schedule 11.06.2014
comment
@Helmut Я скопировал (вроде) тип данных из книги «Основы программного обеспечения». В нем бесконечно много нулей, так что мы можем попрактиковаться в доказательстве того, что нормализует ненужные конструкторы.   -  person András Kovács    schedule 11.06.2014


Ответы (2)


Импорт:

open import Level hiding (zero; suc)
open import Function
open import Relation.Binary.HeterogeneousEquality
  renaming (sym to hsym; trans to htrans; cong to hcong; subst to hsubst)
open import Relation.Binary.PropositionalEquality
open import Data.Nat
open import Data.Fin hiding (_+_)
open import Algebra
open import Data.Nat.Properties
module ℕplus = CommutativeSemiring commutativeSemiring

Я немного изменил ваш inc, чтобы упростить:

inc : ∀ {n} → Bin n → Bin (suc n)
inc zero = 2*n+1 zero
inc (2*n b) = 2*n+1 b
inc (2*n+1 {n} b) = subst (Bin ∘ suc) (ℕplus.+-comm n (suc n)) (2*n (inc b))

Лемма:

lem : ∀ n → 2*n+1 (inc (nat2bin n)) ≅ inc (inc (2*n+1 (nat2bin n)))
lem zero = refl
lem (suc n) = {!!}

Тип отверстия

2*n+1 (inc (inc (nat2bin n))) ≅
      inc
      (subst ((λ {.x} → Bin) ∘ suc) (ℕplus.+-comm (suc n) (suc (suc n)))
       (2*n (inc (inc (nat2bin n)))))

Так что нам понадобится что-то вроде subst-removeable из стандартной библиотеки:

≡-subst-removable : ∀ {a p} {A : Set a}
                    (P : A → Set p) {x y} (eq : x ≡ y) z →
                    P.subst P eq z ≅ z
≡-subst-removable P refl z = refl

Тип

hsym $
  ≡-subst-removable
    (Bin ∘ suc)
    (ℕplus.+-comm (suc n) (suc (suc n)))
    (2*n $ inc $ inc $ nat2bin n)

is

(2*n $ inc $ inc $ nat2bin n) ≅
      subst ((λ {.x} → Bin) ∘ suc) (ℕplus.+-comm (suc n) (suc (suc n)))
      (2*n $ inc $ inc $ nat2bin n)

Практически то, что нам нужно. Теперь мы хотим добавить hcong inc, но компилятор отклоняет это. Вот реализация cong:

cong : ∀ {a b} {A : Set a} {B : A → Set b} {x y}
       (f : (x : A) → B x) → x ≅ y → f x ≅ f y
cong f refl = refl

Итак, x и y должны быть одного типа A, в то время как наш subst меняет тип. Вот реализация hcong, которая нам нужна:

hcong' : {α β γ : Level} {I : Set α} {i j : I}
       -> (A : I -> Set β) {B : {k : I} -> A k -> Set γ} {x : A i} {y : A j}
       -> i ≡ j
       -> (f : {k : I} -> (x : A k) -> B x)
       -> x ≅ y
       -> f x ≅ f y
hcong' _ refl _ refl = refl

И последнее доказательство:

lem : ∀ n → 2*n+1 (inc (nat2bin n)) ≅ inc (inc (2*n+1 (nat2bin n)))
lem zero = refl
lem (suc n) =
  hcong'
    (Bin ∘ suc)
    (ℕplus.+-comm (suc n) (suc (suc n)))
    inc
    $ hsym
      $ ≡-subst-removable
          (Bin ∘ suc)
          (ℕplus.+-comm (suc n) (suc (suc n)))
          (2*n $ inc $ inc $ nat2bin n)

Также мы можем объединить subst-removable и cong:

≡-cong-subst-removable : {α β γ : Level} {I : Set α} {i j : I}
                       -> (A : I -> Set β) {B : {k : I} -> A k -> Set γ}
                       -> (e : i ≡ j)
                       -> (x : A i)
                       -> (f : {k : I} -> (x : A k) -> B x)
                       -> f (subst A e x) ≅ f x
≡-cong-subst-removable _ refl _ _ = refl

lem' : ∀ n → 2*n+1 (inc (nat2bin n)) ≅ inc (inc (2*n+1 (nat2bin n)))
lem' zero = refl
lem' (suc n) = hsym $
  ≡-cong-subst-removable
    (Bin ∘ suc)
    (ℕplus.+-comm (suc n) (suc (suc n)))
    (2*n $ inc $ inc $ nat2bin n)
    inc

Кстати, Пирс имел в виду этот тип данных, я полагаю:

data Bin : Set where
  zero  : Bin
  2*n   : Bin → Bin
  2*n+1 : Bin → Bin

Кстати, ваш надуманный пример можно доказать без дополнительных определений:

contrived-example : {n : ℕ} {f : Fin (n + suc n)}
                  -> f ≅ fromℕ (n + suc n)
                  -> f ≅ fromℕ (suc n + n)
contrived-example {n} eq = htrans eq $ hcong fromℕ $ ≡-to-≅ $ ℕplus.+-comm n (suc n)

Кстати, hsubst-ix1 можно значительно сократить, поскольку вы используете гетерогенное равенство и вам не нужно доказывать равенство типов:

hsubst' : {C1 C2 : Set} {x : C1} {y : C2}
        -> (P : {C : Set} -> C -> Set)
        -> x ≅ y
        -> P x
        -> P y
hsubst' _ refl x = x

contrived-example' : 
  ∀ n
  → (f : Fin (n + suc n)) 
  → (fromℕ (n + suc n) ≅ fromℕ (suc n + n))
  → (f ≅ fromℕ (n + suc n))
  → (f ≅ fromℕ (suc n + n)) 
contrived-example' n f eq p = hsubst' (λ f' → f ≅ f') eq p
person user3237465    schedule 17.06.2014
comment
Это именно тот ответ эксперта, который я искал. - person András Kovács; 17.06.2014
comment
Кроме того, я вижу, насколько полезно определение inc в терминах subst, но мне любопытно, как lem можно доказать с помощью моего первоначального rewrite определения inc. - person András Kovács; 17.06.2014
comment
Не обязательно оригинальный, потому что теперь я вижу, что suc-lem не нужен, но, например, с inc (2*n+1 {n} b) with 2*n $ inc b ... | b' rewrite ℕsr.+-comm n (suc n) = b' - person András Kovács; 17.06.2014
comment
Другими словами: как я могу отменить rewrite аналогично тому, как я могу отменить subst? - person András Kovács; 17.06.2014
comment
Это связано: stackoverflow.com/questions/12498428/ Но что-то пошло не так с этим механизмом в моем коде: lpaste.net/105750 - person user3237465; 17.06.2014
comment
Похоже, что версия 0.16 стандартной библиотеки будет включать icong и icong-≡-subst-removable, которые имеют определения, аналогичные вашим hcong' и ≡-cong-subst-removable. Я бы посоветовал использовать версии из стандартной библиотеки вместо того, чтобы делать их самостоятельно (хотя это очень хороший опыт обучения). - person DrPhil; 16.04.2018
comment
@DrPhil, я предлагаю вообще не использовать гетерогенное равенство. - person user3237465; 16.04.2018

Оказывается, эта проблема чем-то похожа на эту, за исключением того, что здесь конструкторы инъективных типов не не помогло.

Обычно вы можете использовать subst для разнородного равенства, когда очевидно, что два типа на сторонах равенства равны:

hsubst :
  {A    : Set}
  (P    : A → Set)
  {x x' : A}
  → x ≅ x'
  → P x
  → P x' 
hsubst P refl p = p 

Это hsubst почти то же самое, что subst для пропозиционального равенства, за исключением типа равенства. Поскольку от нас требуется знать, что типы x и x' равны, мы могли бы просто преобразовать наше неоднородное доказательство равенства в нормальное, а затем использовать обычное subst.

Однако OP (т.е. я) попытался заменить, используя равенство, у которого были индексированные типы с обеих сторон, и не было очевидно, что индексы были равны. Решение состоит в том, чтобы параметризовать hsubst индексом и потребовать дополнительного доказательства равенства для индексов:

hsubst-ix1 : 
    {I    : Set}
    (C    : I → Set)  
    (P    : ∀ {i} → C i → Set)
    {i i' : I}
    {x    : C i}
    {x'   : C i'}
    → i ≡ i'
    → x ≅ x'
    → P x
    → P x'
hsubst-ix1 C P refl refl p = p

Я немного поэкспериментировал, чтобы выяснить, какие аргументы можно вывести, и результат приведен выше. Вот надуманный пример:

open import Relation.Binary.HeterogeneousEquality hiding (cong)
open import Relation.Binary.PropositionalEquality
open import Data.Nat
open import Data.Fin hiding (_+_)
open import Algebra
open import Data.Nat.Properties
module ℕplus = CommutativeSemiring commutativeSemiring

contrived-example : 
  ∀ n
  → (f : Fin (n + suc n)) 
  → (fromℕ (n + suc n) ≅ fromℕ (suc n + n))
  → (f ≅ fromℕ (n + suc n))
  → (f ≅ fromℕ (suc n + n)) 
contrived-example n f eq p =
  hsubst-ix1
    -- the type constructor to be indexed
    Fin
    -- substitution
    (λ f' → f ≅ f')
    -- proof that the indices are equal
    (cong suc (ℕplus.+-comm n (suc n)))
    -- heterogeneous equality
    eq
    -- original expression
    p
person András Kovács    schedule 11.06.2014