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
  apply add_pos
  apply sq_pos_of_pos
  exact ha
  apply sq_pos_of_pos
  exact hb
  -- 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
  have h2a : 0 < a^2
  · exact sq_pos_of_pos ha
  have h2b : 0 < b^2
  · exact sq_pos_of_pos hb
  exact add_pos h2a h2b
  -- 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
  intro h1 h2 h3
  apply h2 h3
  exact h1 h3
  -- 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
  rw [← sub_nonneg]
  ring
  rw [sub_nonneg]
  -- 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 这个变体。

以下是详细的翻译:

我们尝试使用代换法证明一个定理,这个定理陈述了 `add_le_add_iff_left a : a + b ≤ a + c ↔ b ≤ c` ,在这之前我们先给出它的定义。

定义 `add_le_add_iff_left a : a + b ≤ a + c ↔ b ≤ c` 采用以下形式:
如果当给定常数 `a` 时, `b ≤ c` ,那么就有 `a + b ≤ a + c` ,反之亦然。

注意到这个定理与我们在整数加法上看到的相似。在那里,我们已经知道如果 `b ≤ c` ,那么 `a + b ≤ a + c` (这是加法的单调性)。而且,如果 `a + b ≤ a + c` ,我们可以减去 `a` 来得到 `b ≤ c` 。

下面的定理使用同样的证明方法。

## 定理: `add_le_add_iff_left a : a + b ≤ a + c ↔ b ≤ c` 

证明:

由于 `b ≤ c` ,我们可以使用加法的单调性得到 `a + b ≤ a + c` 。

通过减去 `a` ,我们得到 `b ≤ c` 。

在数学研究中,这个定理对于理解和证明加法性质是非常重要的。它告诉我们,我们可以凭借已知的加法属性来推断和证明未知的属性。
example (a b : ℝ) (hb : 0 ≤ b) : a ≤ a + b := by {
  -- sorry
  calc
    a = a + 0 := by ring
    _ ≤ a + b := by exact (add_le_add_iff_left a).2 hb
  -- 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
  constructor
  · intro h
    rw [h]
    ring
  · intro h
    calc
      a = b - (b - a) := by ring
      _ = b - 0       := by rw [h]
      _ = b           := by ring
  -- sorry
}

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

  • intro
  • apply
  • have
  • constructor