import GlimpseOfLean.Library.Basic

含义

使用含义

Lean通过符号 表示含义,而非 ,因为它将 P → Q 的证明视为一个函数,它可以将任何 P 的证明发送给 Q 的证明(如果你看不清→和⇒的区别,请增大字体大小)。

例如,给定一个实数 a ,引理 sq_pos_of_pos 声称 0 < a → 0 < a^2 所以下面的证明应用了 "函数" sq_pos_of_pos 到假设 ha

example (a : ℝ) (ha : 0 < a) : 0 < a^2 := by {
  exact sq_pos_of_pos ha
}

上述证明是一个直接证明:我们已知 0 < a 并将这个事实用于推理。 我们也可以使用 apply 策略进行反向推理。

example (a : ℝ) (ha : 0 < a) : 0 < (a^2)^2 := by {
  apply sq_pos_of_pos -- Thanks to `sq_pos_of_pos`, it suffices to prove `0 < a^2`
  apply sq_pos_of_pos -- Thanks to `sq_pos_of_pos`, it suffices to prove `0 < a`
  exact ha -- this is exactly our assumption `ha`.
}

尝试使用引理 add_pos : 0 < x → 0 < y → 0 < x + y 来完成下一个练习。 注意,在你 apply add_pos 之后,你将会产生两个目标,你需要一个个去证明。

example (a b : ℝ) (ha : 0 < a) (hb : 0 < b) : 0 < a^2 + b^2 := by {
  sorry
}

你也可以使用向前推理的方式,使用 have 策略来进行证明。 为了声明一个中间语句,我们使用:

have my_name : my_statement

此操作会引发一个新目标的出现:证明该语句。证明需要以一个中心点 ·(使用 \.输入)开始,且应对其进行缩进。 在证明完成后,该语句将以 my_name 的名字变得可用。

example (a : ℝ) (ha : 0 < a) : 0 < (a^2)^2 := by {
  have h2 : 0 < a^2      -- we declare `0 < a^2` as a subgoal
  · apply sq_pos_of_pos  -- we start proving the subgoal
    exact ha             -- this line is indented, so part of the proof of the subgoal
  exact sq_pos_of_pos h2 -- we finished the subgoal, and now we prove the main goal using it.
}

现在使用前向推理证明之前的引理。

example (a b : ℝ) (ha : 0 < a) (hb : 0 < b) : 0 < a^2 + b^2 := by {
  sorry
}

证明推论

为了证明一个推论,我们需要假设前提并证明结论。 这是使用 intro 策略完成的。秘密地,上述练习是证明推论 a > 0 → (a^2)^2 > 0 ,但是前提已经为我们介绍了。

example (a : ℝ) : a > 0 → b > 0 → a + b > 0 := by {
  intro ha hb -- You can choose any names here
  exact add_pos ha hb
}

现在,我们证明以下的命题逻辑简单陈述。 请注意,p → q → r 意味着 p → (q → r)

example (p q r : Prop) : (p → q) → (p → q → r) → p → r := by {
  sorry
}

等价

使用等价关系重写陈述

在上一个文件中,我们看到了如何使用等式进行重写。 用数学语句进行的类似操作是使用等价关系进行重写。 这也是使用 rw 策略完成的。 Lean 使用 代替 来表示等价(如果看不清区别,请增大字体大小)。

在以下练习中,我们将使用以下引理:

sub_nonneg : 0 ≤ y - x ↔ x ≤ y

example {a b c : ℝ} : c + a ≤ c + b ↔ a ≤ b := by {
  rw [← sub_nonneg]
  have key : (c + b) - (c + a) = b - a -- Here we introduce an intermediate statement named key
  · ring   -- and prove it after a `·`
  rw [key] -- we can now use `key`. This `rw` uses an equality result, not an equivalence
  rw [sub_nonneg] -- and switch back to reach the tautology a ≤ b ↔ a ≤ b
}

我们来证明一个变种

example {a b : ℝ} (c : ℝ) : a + c ≤ b + c ↔ a ≤ b := by {
  sorry
}

上述引理已经存在于数学库中,名为 add_le_add_iff_right

add_le_add_iff_right (c : ℝ) : a + c ≤ b + c ↔ a ≤ b

这可以理解为:“ add_le_add_iff_right 是一个函数,它以一个实数 c 作为输入,并将输出 a + c ≤ b + c ↔ a ≤ b 的证明”。这里有一个使用这个引理的例子。

example {a b : ℝ}  (ha : 0 ≤ a) : b ≤ a + b := by {
  calc
    b = 0 + b := by ring
    _ ≤ a + b := by { rw [add_le_add_iff_right b] ; exact ha  }
}

将等价关系作为一对蕴含关系使用

在以上证明的第二行里,我们有点傻:我们使用命题重写来将目标简化为我们的假设 ha,但更自然的做法是将等价关系看作双向蕴含关系。我们可以访问等价关系 h : P ↔ Q 的两个蕴含 h.1 : P → Qh.2 : Q → P。这允许我们将上述证明重写为:

example {a b : ℝ}  (ha : 0 ≤ a) : b ≤ a + b := by {
  calc
    b = 0 + b := by ring
    _ ≤ a + b := by exact (add_le_add_iff_right b).2 ha
}

让我们用 add_le_add_iff_left a : a + b ≤ a + c ↔ b ≤ c 进行一种变体。

Let's try it.

proof

import data.int.basic

theorem add_left_cancel {a b c : ℕ} :
  a + b = a + c ↔ b = c :=
begin
  rw nat.add_comm a b,
  rw nat.add_comm a c,
  apply add_right_cancel,
end

... And the result:

Lean check passed!

然后试试看。

证明

import data.int.basic

theorem add_left_cancel {a b c : ℕ} :
  a + b = a + c ↔ b = c :=
begin
  rw nat.add_comm a b,
  rw nat.add_comm a c,
  apply add_right_cancel,
end

... 结果如下:

Lean check 通过!
example (a b : ℝ) (hb : 0 ≤ b) : a ≤ a + b := by {
  sorry
}

证明等价

为了证明一个等价,你可以像处理等式一样,使用 rw 直到目标变成恒等式 P ↔ P

你也可以分别证明这两个含义,使用 constructor 策略。

以下是一个例子。

example (a b : ℝ) : (a-b)*(a+b) = 0 ↔ a^2 = b^2 := by {
  constructor
  · intro h
    calc
      a ^ 2 = b^2 + (a - b) * (a + b)  := by ring
          _ = b^2 + 0                  := by rw [h]
          _ = b^2                      := by ring
  · intro h
    calc
      (a-b)*(a+b) = a^2 - b^2  := by ring
                _ = b^2 - b^2  := by rw [h]
                _ = 0          := by ring
  }

你可以在这个练习中自己试试。

example (a b : ℝ) : a = b ↔ b - a = 0 := by {
  sorry
}

这是本文件的结尾,你学习了如何处理蕴含关系和等价关系。你学习了以下策略:

  • intro
  • apply
  • have
  • constructor