首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >「SF-LC」6 Logic

「SF-LC」6 Logic

作者头像
零式的天空
发布于 2022-03-14 06:39:12
发布于 2022-03-14 06:39:12
64600
代码可运行
举报
文章被收录于专栏:零域Blog零域Blog
运行总次数:0
代码可运行

We have seen…

  • propositions: factual claims
    • equality propositions (e1 = e2)
    • implications (P → Q)
    • quantified propositions (∀ x, P)
  • proofs: ways of presenting evidence for the truth of a proposition

Prop type

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Check 3 = 3.  (* ===> Prop. A provable prop *)
Check 3 = 4.  (* ===> Prop. A unprovable prop *)

Prop is first-class entity we can

  • name it
  • parametrized!
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Definition is_three (n : nat) : Prop :=
  n = 3.

Check is_three. (* ===> nat -> Prop *)

Properties

In Coq, functions that return propositions are said to define properties of their arguments.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Definition injective {A B} (f : AB) :=
  ∀x y : A, f x = f y → x = y.
Lemma succ_inj : injective S. (* can be read off as "injectivity is a property of S" *)
Proof. 
  intros n m H. injection H as H1. apply H1. Qed.

The equality operator = is also a function that returns a Prop. (property: equality)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Check @eq. (* ===> forall A : Type, A -> A -> Prop *)

Theroems are types, and proofs are existentials.

Slide Q&A - 1.

  1. Prop
  2. Prop
  3. Prop
  4. Not typeable
  5. nat -> nat
  6. nat -> Prop
  7. (3)

think that Big Lambda (the type abstraction) works at type level, accepts type var, substitute and reture a type. forall in Coq is same (the concrete syntax) and only typecheck with Type or its subtype Set & Prop.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Check (∀n:nat, S (pred n)).  (* not typeable *)

Definition foo : (forall n:nat, bool) (* foo: nat -> bool *)
  := fun x => true.

Logical Connectives

noticed that connectives symbols are “unicodize” in book and spacemacs.

Conjuction (logical and)

and is just binary Prop -> Prop -> Prop and associative.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Print "/\".
Inductive and (A B : Prop) : Prop :=  conj : A -> B -> A /\ B
Check and. (* ===> and : Prop -> Prop -> Prop *)
and introduction
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma and_intro : forall A B : Prop, A -> B -> A /\ B.
Proof.
  intros A B HA HB. split.
  - apply HA.
  - apply HB.
Qed.

To prove a conjunction,

  • use the split tactic. It will generate two subgoals,
  • or use apply and_intro., which match the conclusion and give its two premises as your subgoals.
and elimination

if we already have a proof of and, destruct can give us both.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma and_example2' :
  ∀n m : nat, n = 0 ∧ m = 0 → n + m = 0.
Proof.
  intros n m [Hn Hm]. (* = intro H. destruct H. *)
  rewrite Hn. rewrite Hm. reflexivity. Qed.  (* you could use only one *)

Instead of packing into conjunction ∀n m : nat, n = 0 ∧ m = 0 → n + m = 0. why not two separate premises? ∀n m : nat, n = 0 -> m = 0 → n + m = 0. Both are fine in this case but conjunction are useful as intermediate step etc.

Coq Intensive Q: why destruct can work on and? is and inductively defined? A: Yes.

Disjunction (locial or)

or elimination

We need do case analysis (either P or Q should be able to prove the theroem separately!)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma or_example :
  forall n m : nat, n = 0 \/ m = 0 -> n * m = 0.
Proof.
  (* This pattern implicitly does case analysis on [n = 0 \/ m = 0] *)
  intros n m [Hn | Hm]. (* = intro H. destruct H. *)
  - (* Here, [n = 0] *) rewrite Hn. reflexivity.
  - (* Here, [m = 0] *) rewrite Hm. rewrite <- mult_n_O. reflexivity.
Qed.
or introduction

When trying to establish (intro into conclusion) an or, using left or right to pick one side to prove is sufficient.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma or_intro : forall A B : Prop, A -> A \/ B.
Proof.
  intros A B HA.
  left.  (* tactics *)
  apply HA.
Qed.

Falsehood and negation

False?

Recall the princple of explosion: it asserts that, if we assume a contradiction, then any other proposition can be derived. we could define ¬ P (“not P”) as ∀ Q, P → Q..

Coq actually makes a slightly different (but equivalent) choice, defining ¬ P as P → False, where False is a specific contradictory proposition defined in the standard library.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Definition not (P:Prop) := P → False.
Notation "¬x" := (not x) : type_scope.

Prove the princple of explosion:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Theorem ex_falso_quodlibet : forall (P:Prop),
  False -> P.
Proof.
  intros P contra.
  destruct contra.  Qed.  (* 0 cases to prove since ⊥ is not provable. [inversion] also works *)
Inequality
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Notation "x <> y" := (~(x = y)).

Same as SML and OCaml (for structural equality, OCaml uses != for physical equality.)

Proving of negation (or how to prove ¬P)

thinking about as unfold not, i.e. P -> False. so you have an assumptions P that could be intros HP. and the residual goal would be simply False. which is usually proved by some kind of contradiction in hypotheses with tactics discriminate. or contradiction.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Theorem contradiction_implies_anything : forall P Q : Prop,
  (P /\ ~P) -> Q.
Proof.
  intros P Q [HP HNA].                 (* we could [contradiction.] to end the proof here`*)
  unfold not in HNA. apply HNA in HP.  (* HP : False, HNA : P -> False  ⊢  HP: False  *)
  destruct HP.  Qed.                   (* destruct False.  *)
Tactic exfalso.

If you are trying to prove a goal that is nonsensical (e.g., the goal state is false = true), apply ex_falso_quodlibet to change the goal to False. This makes it easier to use assumptions of the form ¬P that may be available in the context — in particular, assumptions of the form x≠y. Since reasoning with ex_falso_quodlibet is quite common, Coq provides a built-in tactic, exfalso, for applying it.

Slide Q&A - 2

?unfold is implicit

  1. only destruct (if we consider intros destruct is also destruct.), ?unfold
  2. none (?unfold)
  3. left.
  4. destruct, unfold, left and right
  5. discrinminate (or inversion)

Truth

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma True_is_true : True.
Proof. apply I. Qed.

I : True is a predefined Prop…

Logical Equivalence

if and only if is just the conjunction of two implications. (so we need split to get 2 subgoals)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Definition iff (P Q : Prop) := (PQ)  (QP).
Notation "P ↔ Q" := (iff P Q)
                    (at level 95, no associativity) : type_scope.

rewrite and reflexivity can be used with iff statements, not just equalities.

Existential Quantification

To prove a statement of the form ∃x, P, we must show that P holds for some specific choice of value for x, known as the witness of the existential.

So we explicitly tell Coq which witness t we have in mind by invoking exists t. then all occurences of that “type variable” would be replaced.

Intro
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma four_is_even : exists n : nat, 4 = n + n.
Proof.
  exists 2. reflexivity.
Qed.
Elim

Below is an interesting question…by intros and destruct we can have equation n = 4 + m in hypotheses.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Theorem exists_example_2 : forall n,
  (exists m, n = 4 + m) ->
  (exists o, n = 2 + o).
Proof.
  intros n [m Hm]. (* note implicit [destruct] here *)
  exists (2 + m).
  apply Hm.  Qed.

Programming with Propositions

Considering writing a common recursive is_in for polymorphic lists. (Though we dont have a polymorphic =? (eqb) defined yet)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Fixpoint is_in {A : Type} (x : A) (l : list A) : bool :=
  match l with
  | [] => false
  | x' :: l' => if (x' =? x) then true else is_in x l'
  end.

Similarly, we can write this function but with disjunction and return a Prop! so we can write function to generate/create statements/propositions! (thx for the idea Prop is first-class)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Fixpoint In {A : Type} (x : A) (l : list A) : Prop :=
  match l with
  | [] => False
  | x' :: l' => x' = x ∨ In x l'
  end.

The whole thing I understood as a type operator (function in type level) and it’s recursive!

Coq dare to do that becuz its total, which is guarded by its termination checker. un-total PL, if having this, would make its type system Turing Complete (thus having Halting Problem). (Recursive Type like ADT/GADT in ML/Haskell is a limited form of recursion allowing no arbitray recursion.)

In_map

I took this one since it’s like a formal version of Property-based Tests!.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma In_map :
  forall (A B : Type) (f : A -> B) (l : list A) (x : A),
    In x l ->
    In (f x) (map f l).
Proof.
  intros A B f l x.
  induction l as [|x' l' IHl'].
  - (* l = nil, contradiction *)
    simpl. intros [].
  - (* l = x' :: l' *)
    simpl. intros [H | H].           (* evaluating [In] gives us 2 cases:  *)
    + rewrite H. left. reflexivity.  (* in head of l *)
    + right. apply IHl'. apply H.    (* in tail of l*)
Qed.

Q & A:

  1. eq is just another inductively defined and doesn’t have any computational content. (satisfication)
  2. Why use Prop instead of bool? See reflection below.

Drawbacks

In particular, it is subject to Coq’s usual restrictions regarding the definition of recursive functions, e.g., the requirement that they be “obviously terminating.” In the next chapter, we will see how to define propositions inductively, a different technique with its own set of strengths and limitations.

Applying Theorems to Arguments.

Check some_theorem print the statement!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Check plus_comm.
(* ===> forall n m : nat, n + m = m + n *)

Coq prints the statement of the plus_comm theorem in the same way that it prints the type of any term that we ask it to Check. Why?

Hmm…I just noticed that!! But I should notice because Propositions are Types! (and terms are proof)

Proof Object

proofs as first-class objects.

After Qed., Coq defined they as Proof Object and the type of this obj is the statement of the theorem.

Provable: some type is inhabited by some thing (having terms).

So I guess when we apply theorems, Coq implicitly use the type of the Proof Object. (it’s already type abstraction) …we will get to there later at ProofObject chapter.

Apply theorem as function

rewrite select variables greedily by default

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma plus_comm3_take3 :
  ∀x y z, x + (y + z) = (z + y) + x.
Proof.
  intros x y z.
  rewrite plus_comm.
  rewrite (plus_comm y z).     (* we can explicitly provide type var! *)
  reflexivity.
Qed.

x y z were some type var and instantiated to values by intros, e.g. x, y, z:nat but we can explicilty pass in to plus_comm, which is a forall type abstraction! (Δ n m. (eq (n + m) (m + n)))

there must be something there in Proof Object so we can apply values to a type-level function

Coq vs. Set Theory

Coq’s logical core, the Calculus of Inductive Constructions, is a metalanguage for math, but differs from other foundations of math e.g. ZFC Set Theory

Functional Extensionality

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(∀x, f x = g x) → f = g

∃f g, (∀x, f x = g x) → f = g

∃f g, (∀x, f x = g x) ∧ f != g    (* negation, consistent but not interesting... *)

In common math practice, two functions f and g are considered equal if they produce the same outputs. This is known as the principle of functional extensionality. Informally speaking, an “extensional property” is one that pertains to an object’s observable behavior. https://en.wikipedia.org/wiki/Extensionality https://en.wikipedia.org/wiki/Extensional_and_intensional_definitions?

This is not built-in Coq, but we can add them as Axioms. Why not add everything?

  1. One or multiple axioms combined might render inconsistency.
  2. Code extraction might be problematic

Fortunately, it is known that adding functional extensionality, in particular, is consistent. consistency: a consistent theory is one that does not contain a contradiction.

Adding Axioms

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Axiom functional_extensionality : forall {X Y: Type}
                                    {f g : X -> Y},
  (forall (x:X), f x = g x) -> f = g.

It’s like Admitted. but alerts we’re not going to fill in later.

Exercise - Proving Reverse with app and with cons are fn-exensionally equivalent.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Fixpoint rev_append {X} (l1 l2 : list X) : list X :=
  match l1 with
  | [] => l2
  | x :: l1' => rev_append l1' (x :: l2)
  end.

Definition tr_rev {X} (l : list X) : list X :=
  rev_append l [].

BTW, this version is tail recursive becuz the recursive call is the last operation needs to performed. (In rev i.e. rev t ++ [h], recursive call is a argument of function ++ and we are CBV.)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Lemma tr_rev_correct : forall X, @tr_rev X = @rev X.

Propositions and Booleans

We’ve seen two different ways of expressing logical claims in Coq:

  1. with booleans (of type bool), ; computational way
  2. with propositions (of type Prop). ; logical way

There’re two ways to define 42 is even:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Example even_42_bool : evenb 42 = true.
Example even_42_prop : ∃k, 42 = double k.

We wanna show there are interchangable.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Theorem even_bool_prop : ∀n,
  evenb n = true ↔ ∃k, n = double k.

In view of this theorem, we say that the boolean computation evenb n reflects the truth of the proposition ∃ k, n = double k.

We can futhur general this to any equations representing as bool or Prop:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Theorem eqb_eq : ∀n1 n2 : nat,
  n1 =? n2 = true ↔ n1 = n2.
Notes on Computability.

However, even they are equivalent from a purely logical perspective, they may not be equivalent operationally.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Fail Definition is_even_prime n :=
  if n = 2 then true
  else false.

Error: The term "n = 2" has type "Prop" which is not a (co-)inductive type.

=, or eq, as any function in Coq, need to be computable and total. And we have no way to tell whether any given proposition is true or false. (…We can only naturally deduce things are inductively defined)

As a consequence, Prop in Coq does not have a universal case analysis operation telling whether any given proposition is true or false, since such an operation would allow us to write non-computable functions. Although general non-computable properties cannot be phrased as boolean computations, it is worth noting that even many computable properties are easier to express using Prop than bool, since recursive function definitions are subject to significant restrictions in Coq.

E.g. Verifying Regular Expr in next chapter.

Doing the same with bool would amount to writing a full regular expression matcher (so we can execute the regex).

Proof by Reflection!
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(* Logically *)
Example even_1000 : ∃k, 1000 = double k.
Proof.500. reflexivity. Qed.

(* Computationally *)
Example even_1000' : evenb 1000 = true.
Proof. reflexivity. Qed.

(* Prove logical version by reflecting in computational version *)
Example even_1000'' : ∃k, 1000 = double k.
Proof. apply even_bool_prop. reflexivity. Qed.

As an extreme example, the Coq proof of the famous 4-color theorem uses reflection to reduce the analysis of hundreds of different cases to a boolean computation.

Classical vs. Constructive Logic

Future Schedule

Proof got messier! Lean on your past PLT experience

As discussion leader

  • having many materials now
  • selected troublesome and interesting ones
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
今天你学C++了吗?——内存管理
前面在C语言阶段的一篇博客 C语言——动态内存分配我们提到过C/C++程序中内存区域的划分~
用户11352420
2024/12/25
1460
今天你学C++了吗?——内存管理
C&C++内存管理
在C语言中我们经常说,局部变量存放在栈区,动态内存开辟的空间是向堆区申请的,只读常量存放在常量区等等。其实这里我们所说的区域都是虚拟进程地址空间的一部分,具体划分如下:
始终学不会
2023/03/28
1.4K0
C&C++内存管理
C++:内存管理|new和delete
为什么需要内存管理呢??因为我们在程序的运行过程中会需要各种各样的数据,而我们根据数据的不同存储在不同的区域里面,是为了更高效地处理数据。而C语言相比Java来说在内存的权限上尽可能给了程序员更多的操作空间,这也是为什么C更追求性能。
小陈在拼命
2024/03/01
2510
C++:内存管理|new和delete
C++内存管理
方便管理,程序中需要不同类型的数据,主要是生命周期,比如当我们需要一个全局变量时,那么这个变量对应的是放在数据段中。还有一些局部变量,存放在栈中。
南桥
2024/07/26
1630
C++内存管理
【C++】动态内存管理
了解了这些之后,我们再来通过一个经典练习题深入理解一下内存区域的划分,如下代码:
修修修也
2024/04/20
2180
【C++】动态内存管理
C/C++内存管理
malloc和calloc的区别在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0,malloc不为初始化,而realloc是扩容分为原地扩容和异地扩容。
用户11375356
2024/11/22
990
C/C++内存管理
C/C++内存管理
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区) globalVar在哪里?____ staticGlobalVar在哪里?____ staticVar在哪里?____ localVar在哪里?____ num1 在哪里?____ char2在哪里?____ *char2在哪里?____ pChar3在哪里?____ *pChar3在哪里?____ ptr1在哪里?____ *ptr1在哪里?____ 是不是有点乱,看一下图解吧。
小志biubiu
2025/02/27
1380
C/C++内存管理
[C++]内存管理
2.内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
IT编程爱好者
2023/04/30
9860
[C++]内存管理
【C++内存管理】:new与delete,operator new与operator delete
📝前言: 上篇文章【C++高潮:类与对象】我们对C++的类与对象的知识点进行了讲解。 这篇文章我们在C语言内存管理的基础上探讨一下C++内存的管理: 1,C/C++内存分布 2,C语言内存管理 3,C++内存管理方式 4,operator new与operator delete 5,new和delete的实现原理 6,定位new表达式 7,malloc/free和new/delete的区别
用户11029137
2025/03/12
4640
【C++】内存管理
C++提供了对内存的精细控制,允许程序员以动态和手动的方式分配和释放内存。这种能力既带来强大的灵活性,也伴随着一定的挑战。
_小羊_
2024/10/16
1910
【C++】内存管理
C++从入门到精通——C++动态内存管理
C++动态内存管理涉及使用new和delete操作符来动态分配和释放堆内存。new用于在堆上分配内存并初始化对象,delete用于释放先前分配的内存。此外,C++还提供了智能指针如std::unique_ptr和std::shared_ptr来自动管理内存,以避免内存泄漏和悬挂指针。这些智能指针在超出作用域时会自动删除其所指向的对象。
鲜于言悠
2024/04/22
4360
C++从入门到精通——C++动态内存管理
【C++】探索C++内存管理:机制揭秘与内存安全
需要注意的是,C标准库中的malloc函数的具体实现可能因编译器和操作系统的不同而有所差异,上述步骤仅为一种常见的实现方式。
大耳朵土土垚
2024/05/03
2430
【C++】探索C++内存管理:机制揭秘与内存安全
【C/C++】图文题目吃透内存管理
学习目标:了解C/C++内存的分段情况,C++内容管理方式、operator new与operator delete函数 、new和delete的实现原理、定位new的表达式、最后介绍相关面试题的解析
平凡的人1
2022/11/15
1.2K0
【C/C++】图文题目吃透内存管理
初识C++ · 内存管理
语言不同,内存分布是相同的,对于局部变量都是放在栈上,全局变量都是放在静态区(数据段),动态开辟的都是从堆中开辟,const修饰的变量也是都放在常量区(代码段)
_lazy
2024/10/16
1440
初识C++ · 内存管理
【C++】C/C++内存管理
好的,并没有初始化。 那这样看的话,C++搞出new这些东西和C语言的malloc这些对于内置类型的操作好像除了用法之外也没有什么很大的区别。 那所以呢? C++搞出这些东西更多的是为了自定义类型,那new和delete操作自定义类型我们后面也会专门讲解,先不急。
YIN_尹
2024/01/23
2940
【C++】C/C++内存管理
C++第七弹 -- C/C++内存管理
在C/C++编程中,内存管理是至关重要的一个环节。程序员需要合理地分配和释放内存,以确保程序能够正常运行,避免内存泄漏和崩溃。本文将深入探讨C/C++内存管理机制,从内存分布、动态内存管理方式、new和delete的实现原理到定位new表达式,以及malloc/free和new/delete的区别,全面解析C/C++内存管理的方方面面。
用户11317877
2024/10/16
1900
C++第七弹 -- C/C++内存管理
C++奇迹之旅:C++内存管理的机制初篇
数据段:也叫静态数据段或初始化数据段,用于存储程序中的全局变量和静态变量,这些变量在程序启动时就已经分配好内存空间并初始化。 代码段:也叫文本段或指令段,用于存储程序的可执行指令代码。 这部分内存区域通常是只读的,程序在运行时不能修改代码段中的内容。
学习起来吧
2024/05/06
3190
C++奇迹之旅:C++内存管理的机制初篇
【C++】C/C++内存管理
程序的运行本质上就是存储一些指令,存储一些数据,对于数据,由于的需求的不同,有的可能使用一下就行了,有的需要长期使用,有的不能修改,因此内存中划分成不同的区域存放相关的一些数据(本文主要目的在于介绍C++相关内存管理方式,对于内存浅浅介绍一些知识,具体相关内存底层知识请移步其他文章。)
ZLRRLZ
2024/12/13
2350
【C++】C/C++内存管理
【C++】内存管理
1. 栈 又叫堆栈 -- 非静态局部变量 / 函数参数 / 返回值等等,栈是向下增长的。
啊QQQQQ
2024/11/19
1390
【C++】内存管理
【C++基础篇】学习C++就看这篇--->内存管理之new和delete
2️⃣内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(在后续Linux博客的更新中会进行详细介绍)
HABuo
2025/07/15
1570
【C++基础篇】学习C++就看这篇--->内存管理之new和delete
相关推荐
今天你学C++了吗?——内存管理
更多 >
LV.0
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验