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