Documentation

Mathlib.Tactic.FunProp

Tactic fun_prop for proving function properties like Continuous f, Differentiable ℝ f, ... #

Basic use: Using the fun_prop tactic should be as simple as:

example : Continuous (fun x : ℝ => x * sin x) := by fun_prop

Mathlib sets up fun_prop for many different properties like Continuous, Measurable, Differentiable, ContDiff, etc., so fun_prop should work for such goals. The basic idea behind fun_prop is that it decomposes the function into a composition of elementary functions and then checks if every single elementary function is, e.g., Continuous.

For ContinuousAt/On/Within variants, one has to specify a tactic to solve potential side goals with disch:=<tactic>. For example:

example (y : ℝ) (hy : y ≠ 0) : ContinuousAt (fun x : ℝ => 1/x) y := by fun_prop (disch:=assumption)

Basic debugging: The most common issue is that a function is missing the appropriate theorem. For example:

import Mathlib.Data.Complex.Exponential
example : Continuous (fun x : ℝ => x * Real.sin x) := by fun_prop

Fails with the error:

`fun_prop` was unable to prove `Continuous fun x => x * x.sin`

Issues:
  No theorems found for `Real.sin` in order to prove `Continuous fun x => x.sin`

This can be easily fixed by importing Mathlib.Analysis.SpecialFunctions.Trigonometric.Basic where the theorem Real.continuous_sin is marked with the fun_prop attribute.

When the issue is not simply a few missing theorems, you can turn on the option:

set_option trace.Meta.Tactic.fun_prop true

This will display the trace of how fun_prop steps through the whole expression.

Basic setup for a new function property:

To set up fun_prop for a new function property, you have to:

  1. Mark the function property with the fun_prop attribute when defining it:
@[fun_prop]
def Continuous (f : X → Y) := ...

or later on with:

attribute [fun_prop] Continuous
  1. Mark basic lambda calculus theorems. The bare minimum is the identity, constant, and composition theorems:
@[fun_prop]
theorem continuous_id : Continuous (fun x => x) := ...

@[fun_prop]
theorem continuous_const (y : Y) : Continuous (fun x => y) := ...

@[fun_prop]
theorem continuous_comp (f : Y → Z) (g : X → Y) (hf : Continuous f) (hg : Continuous g) :
  Continuous (fun x => f (g x)) := ...

The constant theorem is not absolutely necessary as, for example, IsLinearMap ℝ (fun x => y) does not hold, but we almost certainly want to mark it if it is available.

You should also provide theorems for Prod.mk, Prod.fst, and Prod.snd:

@[fun_prop]
theorem continuous_fst (f : X → Y × Z) (hf : Continuous f) : Continuous (fun x => (f x).fst) := ...
@[fun_prop]
theorem continuous_snd (f : X → Y × Z) (hf : Continuous f) : Continuous (fun x => (f x).snd) := ...
@[fun_prop]
theorem continuous_prod_mk (f : X → Y) (g : X → Z) (hf : Continuous f) (hg : Continuous g) :
    Continuous (fun x => Prod.mk (f x) (g x)) := ...
  1. Mark function theorems. They can be stated simply as:
@[fun_prop]
theorem continuous_neg : Continuous (fun x => - x) := ...

@[fun_prop]
theorem continuous_add : Continuous (fun x : X × X => x.1 + x.2) := ...

where functions of multiple arguments have to be appropriately uncurried. Alternatively, they can be stated in compositional form as:

@[fun_prop]
theorem continuous_neg (f : X → Y) (hf : Continuous f) : Continuous (fun x => - f x) := ...

@[fun_prop]
theorem continuous_add (f g : X → Y) (hf : Continuous f) (hg : Continuous g) :
  Continuous (fun x => f x + g x) := ...

It is enough to provide function theorems in either form. It is mainly a matter of convenience.

With such a basic setup, you should be able to prove the continuity of basic algebraic expressions.

When marking theorems, it is a good idea to check that a theorem has been registered correctly. You can do this by turning on the Meta.Tactic.fun_prop.attr option. For example: (note that the notation f x + g x is just syntactic sugar for @HAdd.hAdd X Y Y _ (f x) (g x))

set_option trace.Meta.Tactic.fun_prop.attr true
@[fun_prop]
theorem continuous_add (f g : X → Y) (hf : Continuous f) (hg : Continuous g) :
  Continuous (fun x => @HAdd.hAdd X Y Y _ (f x) (g x)) := ...

displays:

[Meta.Tactic.fun_prop.attr] function theorem: continuous_add
    function property: Continuous
    function name: HAdd.hAdd
    main arguments: [4, 5]
    applied arguments: 6
    form: compositional form

This indicates that the theorem continuous_add states the continuity of HAdd.hAdd in the 4th and 5th arguments and the theorem is in compositional form.

Advanced #

Type of Theorems #

There are four types of theorems that are used a bit differently.