Как делать кейсы с индуктивным типом в Coq

Я хочу использовать тактику destruct, чтобы доказать утверждение случаями. Я прочитал пару примеров в Интернете, и я запутался. Может кто-нибудь объяснить это лучше?

Вот небольшой пример (есть и другие способы решения, но попробуйте использовать destruct):

 Inductive three := zero 
                  | one 
                  | two.
 Lemma has2b2: forall a:three, a<>zero /\ a<>one -> a=two.

Теперь несколько примеров в Интернете предлагают сделать следующее:

intros. destruct a.

В этом случае я получаю:

3 subgoals H : zero <> zero /\ zero <> one
______________________________________(1/3) 
zero = two

______________________________________(2/3) 
one = two

______________________________________(3/3) 
two = two

Итак, я хочу доказать, что первые два случая невозможны. Но машина перечисляет их как подцели и хочет, чтобы я их ДОКАЗАЛ ... что невозможно.

Резюме: Как именно отбросить невозможные случаи?

Я видел несколько примеров с использованием inversion, но не понимаю процедуры.

Наконец, что произойдет, если моя лемма зависит от нескольких индуктивных типов, а я все еще хочу охватить ВСЕ случаи?


person Skuge    schedule 25.07.2011    source источник


Ответы (2)


Как отказаться от невозможного? Что ж, это правда, что первые два обязательства невозможно доказать, но обратите внимание, что они имеют противоречивые предположения (zero <> zero и one <> one соответственно). Так что вы сможете доказать эти цели с помощью tauto (есть также более примитивные тактики, которые помогут, если вам интересно).

inversion - это более продвинутая версия destruct. В дополнение к «разрушению» индуктивности он иногда генерирует некоторые равенства (которые могут вам понадобиться). Сама по себе это простая версия induction, которая дополнительно генерирует для вас гипотезу индукции.

Если у вас есть несколько индуктивных типов в вашей цели, вы можете destruct/invert их один за другим.

Более подробный обзор:

Inductive three := zero | one | two .

Lemma test : forall a, a <> zero /\ a <> one -> a = two.
Proof.
  intros a H.
  destruct H. (* to get two parts of conjunction *)
  destruct a. (* case analysis on 'a' *)
(* low-level proof *)
  compute in H. (* to see through the '<>' notation *)
  elimtype False. (* meaning: assumptions are contradictory, I can prove False from them *)
  apply H.
  reflexivity.
(* can as well be handled with more high-level tactics *)
  firstorder.
(* the "proper" case *)
  reflexivity.
Qed.
person akoprowski    schedule 26.07.2011
comment
Не могли бы вы показать мне другой способ доказать гол без тауто? Если вы не против опубликовать кусок кода, было бы здорово. - person Skuge; 26.07.2011
comment
Я отредактировал ответ, включив в него полное низкоуровневое доказательство. Такой низкоуровневый материал полезен для изучения вещей, но в целом вы бы просто покончили с этим с помощью такой тактики, как tauto или firstorder - person akoprowski; 26.07.2011

Если вы видите невозможную цель, есть две возможности: либо вы допустили ошибку в своей стратегии доказательства (возможно, ваша лемма неверна), либо гипотезы противоречат друг другу.

Если вы думаете, что гипотезы противоречат друг другу, вы можете установить цель False, чтобы немного усложнить задачу. elimtype False достигает этого. Часто вы доказываете False, доказывая предложение P и его отрицание ~P; тактика absurd P выводит любую цель из P и ~P. Если есть конкретная гипотеза, которая противоречит, contradict H установит цель равной ~H, или если гипотеза является отрицанием ~A, тогда цель будет A (более сильная, чем ~ ~A, но обычно более удобная). Если одна конкретная гипотеза явно противоречит, contradiction H или просто contradiction докажет любую цель.

Существует множество тактик, использующих гипотезы индуктивного типа. Выяснение того, какой из них использовать, в основном зависит от опыта. Вот основные из них (но вскоре вы столкнетесь с случаями, которые здесь не описаны):

  • destruct просто разбивает гипотезу на несколько частей. Он теряет информацию о зависимостях и рекурсии. Типичный пример - destruct H, где H - соединение H : A /\ B, которое разделяет H на две независимые гипотезы типов A и B; или дважды destruct H, где H - дизъюнкция H : A \/ B, которая разделяет доказательство на два разных подконтрольных доказательства, одно с гипотезой A, а другое с гипотезой B.
  • case_eq похож на destruct, но сохраняет связи, которые эта гипотеза имеет с другими гипотезами. Например, destruct n, где n : nat разбивает доказательство на два подконтрольных доказательства, одно для n = 0 и одно для n = S m. Если n используется в других гипотезах (т. Е. У вас есть H : P n), вам может потребоваться помнить, что n, который вы разрушили, - это тот же n, который использовался в этих гипотезах: case_eq n делает это.
  • inversion выполняет анализ случая по типу гипотезы. Это особенно полезно, когда есть зависимости в типе гипотезы, которые destruct забыл бы. Обычно вы используете case_eq для гипотез в Set (где уместно равенство) и inversion для гипотез в Prop (которые имеют очень зависимые типы). Тактика inversion оставляет позади множество равенств, и за ней часто следует subst, чтобы упростить гипотезы. Тактика inversion_clear - простая альтернатива inversion; subst, но теряет немного информации.
  • induction означает, что вы собираетесь доказать цель индукцией (= рекурсией) по данной гипотезе. Например, induction n, где n : nat означает, что вы выполните целочисленную индукцию и докажете базовый случай (n заменен на 0) и индуктивный случай (n заменен на m+1).

Ваш пример достаточно прост, чтобы вы могли доказать его как «очевидный анализ случая на a».

Lemma has2b2: forall a:three, a<>zero/\a<>one ->a=two.
Proof. destruct a; tauto. Qed.

Но давайте посмотрим на кейсы, сгенерированные тактикой destruct, т.е. после всего intros; destruct a.. (Случай, когда a равно one, является симметричным; последний случай, когда a равно two, очевиден по рефлексивности.)

H : zero <> zero /\ zero <> one
============================
 zero = two

Цель кажется невыполнимой. Мы можем сообщить об этом Coq, и здесь он может автоматически обнаружить противоречие (zero=zero очевидно, а остальное - тавтология первого порядка, обрабатываемая тактикой tauto).

elimtype False. tauto.

На самом деле tauto работает, даже если вы не начнете с того, что не скажете Coq не беспокоиться о цели, а сначала написали tauto без elimtype False (в IIRC этого не было в старых версиях Coq). Вы можете увидеть, что делает Coq с tauto тактикой, написав info tauto. Coq сообщит вам, какой сценарий проверки сгенерировал tauto тактика. Это не очень просто, поэтому давайте посмотрим на ручное доказательство этого случая. Во-первых, давайте разделим гипотезу (которая представляет собой соединение) на две части.

destruct H as [H0 H1].

Теперь у нас есть две гипотезы, одна из которых zero <> zero. Это явно неверно, потому что это отрицание zero = zero, что явно верно.

contradiction H0. reflexivity.

Мы можем более подробно рассмотреть, что делает тактика contradiction. (info contradiction покажет, что происходит под сценой, но опять же, это не для новичков). Мы утверждаем, что цель верна, потому что гипотезы противоречивы, поэтому мы можем доказать что угодно. Итак, давайте установим промежуточную цель на False.

assert (F : False).

Запустите red in H0., чтобы увидеть, что zero <> zero на самом деле является обозначением для ~(zero=zero), которое, в свою очередь, определяется как значение zero=zero -> False. Итак, False это заключение H0:

apply H0.

А теперь нам нужно доказать, что zero=zero, то есть

reflexivity.

Теперь мы доказали наше утверждение о False. Остается доказать, что False подразумевает нашу цель. Ну, False подразумевает любую цель, это ее определение (False определяется как индуктивный тип с нулевым регистром).

destruct F.
person Gilles 'SO- stop being evil'    schedule 26.07.2011