-
Notifications
You must be signed in to change notification settings - Fork 297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Merged by Bors] - feat(data/sign): the sign function #12835
Closed
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
9f61f6e
feat(data/sign): the sign function
ericrbg 4b75a80
lintfix
ericrbg 506be59
Merge branch 'master' into sign
ericrbg db66169
some progress
ericrbg 6c64422
wip
ericrbg ed8db43
bundle sign as a monoid_with_zero_hom
ericrbg ccc1463
Update src/data/sign.lean
ericrbg d0a07a5
various improvements
ericrbg 4d667d6
fintype instance
ericrbg 391d6a1
Merge branch 'master' into sign
ericrbg 4550b5a
remove neg_zero
ericrbg 1f0e3a5
golf
ericrbg f70b195
Apply suggestions from code review
ericrbg f281e92
reviewer suggestions
ericrbg 234cabc
don't use autogenerated names
ericrbg b4f62ef
Update src/data/sign.lean
ericrbg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
/- | ||
Copyright (c) 2022 Eric Rodriguez. All rights reserved. | ||
Released under Apache 2.0 license as described in the file LICENSE. | ||
Authors: Eric Rodriguez | ||
-/ | ||
import order.basic | ||
import algebra.algebra.basic | ||
import tactic.derive_fintype | ||
|
||
/-! | ||
# Sign function | ||
|
||
This file defines the sign function for types with zero and a decidable less-than relation, and | ||
proves some basic theorems about it. | ||
-/ | ||
|
||
/-- The type of signs. -/ | ||
@[derive [decidable_eq, inhabited, fintype]] | ||
inductive sign_type | ||
| zero | neg | pos | ||
|
||
namespace sign_type | ||
|
||
instance : has_zero sign_type := ⟨zero⟩ | ||
instance : has_one sign_type := ⟨pos⟩ | ||
|
||
instance : has_neg sign_type := | ||
⟨λ s, match s with | ||
| neg := pos | ||
| zero := zero | ||
| pos := neg | ||
end⟩ | ||
|
||
@[simp] lemma zero_eq_zero : zero = 0 := rfl | ||
@[simp] lemma neg_eq_neg_one : neg = -1 := rfl | ||
@[simp] lemma pos_eq_one : pos = 1 := rfl | ||
|
||
/-- The multiplication on `sign_type`. -/ | ||
def mul : sign_type → sign_type → sign_type | ||
| neg neg := pos | ||
| neg zero := zero | ||
| neg pos := neg | ||
| zero _ := zero | ||
| pos h := h | ||
|
||
instance : has_mul sign_type := ⟨mul⟩ | ||
|
||
/-- The less-than relation on signs. -/ | ||
inductive le : sign_type → sign_type → Prop | ||
| of_neg (a) : le neg a | ||
| zero : le zero zero | ||
| of_pos (a) : le a pos | ||
|
||
instance : has_le sign_type := ⟨le⟩ | ||
|
||
instance : decidable_rel le := | ||
λ a b, by cases a; cases b; exact is_false (by rintro ⟨⟩) <|> exact is_true (by constructor) | ||
|
||
/- We can define a `field` instance on `sign_type`, but it's not mathematically sensible, | ||
so we only define the `comm_group_with_zero`. -/ | ||
instance : comm_group_with_zero sign_type := | ||
{ zero := 0, | ||
one := 1, | ||
mul := (*), | ||
inv := id, | ||
mul_zero := λ a, by cases a; refl, | ||
zero_mul := λ a, by cases a; refl, | ||
mul_one := λ a, by cases a; refl, | ||
one_mul := λ a, by cases a; refl, | ||
mul_inv_cancel := λ a ha, by cases a; trivial, | ||
mul_comm := λ a b, by casesm* _; refl, | ||
mul_assoc := λ a b c, by casesm* _; refl, | ||
exists_pair_ne := ⟨0, 1, by rintro ⟨⟩⟩, | ||
inv_zero := rfl } | ||
|
||
instance : linear_order sign_type := | ||
{ le := (≤), | ||
le_refl := λ a, by cases a; constructor, | ||
le_total := λ a b, by casesm* _; dec_trivial, | ||
le_antisymm := λ a b ha hb, by casesm* _; refl, | ||
le_trans := λ a b c hab hbc, by casesm* _; constructor, | ||
decidable_le := le.decidable_rel } | ||
|
||
instance : has_distrib_neg sign_type := | ||
{ neg_neg := λ x, by cases x; refl, | ||
neg_mul := λ x y, by casesm* _; refl, | ||
mul_neg := λ x y, by casesm* _; refl, | ||
..sign_type.has_neg } | ||
|
||
/-- `sign_type` is equivalent to `fin 3`. -/ | ||
def fin3_equiv : sign_type ≃* fin 3 := | ||
{ to_fun := λ a, a.rec_on 0 (-1) 1, | ||
inv_fun := λ a, match a with | ||
| ⟨0, h⟩ := 0 | ||
| ⟨1, h⟩ := 1 | ||
| ⟨2, h⟩ := -1 | ||
| ⟨n+3, h⟩ := (h.not_le le_add_self).elim | ||
end, | ||
left_inv := λ a, by cases a; refl, | ||
right_inv := λ a, match a with | ||
| ⟨0, h⟩ := rfl | ||
| ⟨1, h⟩ := rfl | ||
| ⟨2, h⟩ := rfl | ||
| ⟨n+3, h⟩ := (h.not_le le_add_self).elim | ||
end, | ||
map_mul' := λ x y, by casesm* _; refl } | ||
|
||
section cast | ||
|
||
variables {α : Type*} [has_zero α] [has_one α] [has_neg α] | ||
|
||
/-- Turn a `sign_type` into zero, one, or minus one. This is a coercion instance, but note it is | ||
only a `has_coe_t` instance: see note [use has_coe_t]. -/ | ||
def cast : sign_type → α | ||
| zero := 0 | ||
| pos := 1 | ||
| neg := -1 | ||
|
||
instance : has_coe_t sign_type α := ⟨cast⟩ | ||
|
||
@[simp] lemma cast_eq_coe (a : sign_type) : (cast a : α) = a := rfl | ||
|
||
@[simp] lemma coe_zero : ↑(0 : sign_type) = (0 : α) := rfl | ||
@[simp] lemma coe_one : ↑(1 : sign_type) = (1 : α) := rfl | ||
@[simp] lemma coe_neg_one : ↑(-1 : sign_type) = (-1 : α) := rfl | ||
|
||
end cast | ||
|
||
/-- `sign_type.cast` as a `mul_with_zero_hom`. -/ | ||
@[simps] def cast_hom {α} [mul_zero_one_class α] [has_distrib_neg α] : sign_type →*₀ α := | ||
{ to_fun := cast, | ||
map_zero' := rfl, | ||
map_one' := rfl, | ||
map_mul' := λ x y, by cases x; cases y; simp } | ||
|
||
end sign_type | ||
|
||
variables {α : Type*} | ||
|
||
open sign_type | ||
|
||
section preorder | ||
|
||
variables [has_zero α] [preorder α] [decidable_rel ((<) : α → α → Prop)] {a : α} | ||
|
||
/-- The sign of an element is 1 if it's positive, -1 if negative, 0 otherwise. -/ | ||
def sign : α →o sign_type := | ||
⟨λ a, if 0 < a then 1 else if a < 0 then -1 else 0, | ||
λ a b h, begin | ||
dsimp, | ||
split_ifs with h₁ h₂ h₃ h₄ _ _ h₂ h₃; try {constructor}, | ||
{ cases lt_irrefl 0 (h₁.trans $ h.trans_lt h₃) }, | ||
{ cases h₂ (h₁.trans_le h) }, | ||
{ cases h₄ (h.trans_lt h₃) } | ||
end⟩ | ||
|
||
lemma sign_apply : sign a = ite (0 < a) 1 (ite (a < 0) (-1) 0) := rfl | ||
|
||
@[simp] lemma sign_zero : sign (0 : α) = 0 := by simp [sign_apply] | ||
@[simp] lemma sign_pos (ha : 0 < a) : sign a = 1 := by rwa [sign_apply, if_pos] | ||
@[simp] lemma sign_neg (ha : a < 0) : sign a = -1 := by rwa [sign_apply, if_neg $ asymm ha, if_pos] | ||
|
||
end preorder | ||
|
||
section linear_order | ||
|
||
variables [has_zero α] [linear_order α] {a : α} | ||
|
||
@[simp] lemma sign_eq_zero_iff : sign a = 0 ↔ a = 0 := | ||
begin | ||
refine ⟨λ h, _, λ h, h.symm ▸ sign_zero⟩, | ||
rw [sign_apply] at h, | ||
split_ifs at h; cases h, | ||
exact (le_of_not_lt h_1).eq_of_not_lt h_2 | ||
end | ||
|
||
lemma sign_ne_zero : sign a ≠ 0 ↔ a ≠ 0 := | ||
sign_eq_zero_iff.not | ||
|
||
end linear_order | ||
|
||
section linear_ordered_ring | ||
|
||
variables [linear_ordered_ring α] {a b : α} | ||
|
||
/- I'm not sure why this is necessary, see https://leanprover.zulipchat.com/#narrow/stream/ | ||
113488-general/topic/type.20class.20inference.20issues/near/276937942 -/ | ||
local attribute [instance] linear_ordered_ring.decidable_lt | ||
|
||
/-- `sign` as a `monoid_with_zero_hom` for a nontrivial ordered semiring. Note that linearity | ||
is required; consider ℂ with the order `z ≤ w` iff they have the same imaginary part and | ||
`z - w ≤ 0` in the reals; then `1 + i` and `1 - i` are incomparable to zero, and thus we have: | ||
`0 * 0 = sign (1 + i) * sign (1 - i) ≠ sign 2 = 1`. (`complex.ordered_comm_ring`) -/ | ||
def sign_hom : α →*₀ sign_type := | ||
{ to_fun := sign, | ||
map_zero' := sign_zero, | ||
map_one' := sign_pos zero_lt_one, | ||
map_mul' := λ x y, by | ||
rcases lt_trichotomy x 0 with hx | hx | hx; rcases lt_trichotomy y 0 with hy | hy | hy; | ||
simp only [sign_zero, mul_zero, zero_mul, sign_pos, sign_neg, hx, hy, mul_one, neg_one_mul, | ||
neg_neg, one_mul, mul_pos_of_neg_of_neg, mul_neg_of_neg_of_pos, neg_zero', | ||
mul_neg_of_pos_of_neg, mul_pos] } | ||
|
||
end linear_ordered_ring |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we get
-0 = 0
and--1 = 1
via some other instance below?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just added
neg_zero'
in another PR, and so it's fine because of the distrib neg. We have neg_neg as we have an involutive negation