field_simp

field_simp は,体における等式を示す際の「分母を払う」操作に対応するタクティクです.

import Mathlib.Tactic.FieldSimp
import Mathlib.Tactic.Ring

example (n m : Rat) : n * m = ((n + m) ^ 2 - n ^ 2 - m ^ 2 ) / 2 := by
  -- 分母を払う
  field_simp

  -- Rat は可換環なので, 示すべきことが言える
  ring

分母がゼロでないことが判らない場合は動作しません.分母がゼロでないことを証明してローカルコンテキストに加えると動作することがあります.

example {x y z : Rat} (hy : y = z ^ 2 + 1) : (x + 2 * y) / y = x / y + 2 := by
  -- 最初 `field_simp` は動作しない
  fail_if_success field_simp

  -- 分母がゼロでないことを示す
  have ypos : y ≠ 0 := by
    rw [hy]
    nlinarith

  -- 動作するようになった
  field_simp

制約

field_simp という名前の通り,割り算が体の割り算でなければ動作しません.たとえば 自然数 Nat における割り算は field_simp では扱うことができず,次のコード例のように工夫する必要があります.

example (n m : Nat) : n * m = ((n + m) ^ 2 - n ^ 2 - m ^ 2 ) / 2 := by
  -- field_simp は動作しない
  fail_if_success field_simp

  -- 分母を払う
  symm
  apply Nat.div_eq_of_eq_mul_right (by simp_arith)

  -- `(n + m) ^ 2` を展開する
  rw [show (n + m) ^ 2 = n ^ 2 + 2 * n * m + m ^ 2 from by ring]

  -- 打消し合う項を消して簡単にすれば,示すべきことが言える
  simp [add_assoc, mul_assoc]

また field_simp の扱うのは等式のみで,順序関係は扱いません.体の定義に順序関係は含まれていないので,体を扱うタクティクとしては自然なことかもしれません.

variable (x y : Rat)

example : x * y ≤ (x ^ 2 + y ^ 2) / 2 := by
  -- 何も起こらない
  fail_if_success field_simp

  suffices x ^ 2 - 2 * x * y + y ^ 2 ≥ 0 from by
    linarith
  calc
    x ^ 2 - 2 * x * y + y ^ 2 = (x - y) ^ 2 := by ring
    _ ≥ 0 := by apply sq_nonneg

example (h : x = y) : x * y = (x ^ 2 + y ^ 2) / 2 := by
  -- 等式ならば扱える
  field_simp

  -- ゴールの分母を払うことができた
  show x * y * 2 = x ^ 2 + y ^ 2

  rw [h]
  ring