Zulip Chat Archive
Stream: mathlib4
Topic: Rephrasing Matrix operation for more convenient proving
Bernardo Borges (May 14 2024 at 14:02):
Hello everyone, I am starting to prove my Addition rule for Matrices that represent PseudoBoolean restrictions:
import Mathlib.Data.Fin.Tuple.Reflection
import Mathlib.Data.Matrix.Notation
open FinVec BigOperators
def PBSum (cs : Matrix (Fin n) (Fin 2) ℕ) (xs : Fin n → Fin 2) :=
∑ i, ((cs i) 0 * xs i + (cs i) 1 * (1 - xs i))
def PBIneq {n : ℕ} (cs : Matrix (Fin n) (Fin 2) ℕ) (xs : Fin n → Fin 2) (const : ℕ) :=
PBSum cs xs ≥ const
-- Addition
-- ∑i (a i * l i) ≥ A
-- ∑i (b i * l i) ≥ B
-- ⊢
-- ∑i ((a i + b i) * l i) ≥ A + B
theorem Addition
{xs : Fin n → Fin 2}
{as : Matrix (Fin n) (Fin 2) ℕ} {A : ℕ} (ha : PBIneq as xs A)
{bs : Matrix (Fin n) (Fin 2) ℕ} {B : ℕ} (hb : PBIneq bs xs B)
: PBIneq (tighten $ as + bs) xs (A + B) := by
rw [PBIneq,PBSum,tighten] at *
sorry
Now, this tighten
function below is meant to cancel out terms, since each row of the matrix represents the coefficient of variables and , with the relationship and . This is what I came up with:
import Mathlib.Data.Fin.Tuple.Reflection
import Mathlib.Data.Matrix.Notation
open BigOperators FinVec
/--
For each row, I want to have the elements cancel out, so one of them will always be zero
Ex: row [1,0] -> [1,0]
row [2,1] -> [1,0]
row [1,5] -> [0,4]
-/
def tighten (as : Matrix (Fin n) (Fin 2) ℕ) : Matrix (Fin n) (Fin 2) ℕ :=
(as.map Int.ofNat) * !![1,-1;-1,1] |>.map Int.toNat
-- Proving with this matrix multiplication may get challenging
#eval tighten !![1,0;1,0] = !![1,0;1,0]
#eval tighten !![1,1;1,0] = !![0,0;1,0]
#eval tighten !![1,0;1,2] = !![1,0;0,1]
Where this matrix just want to subtract one column from another and leave 0 if it should be negative. Firstly I ask, will this complicate my Addition
proof? I have a guess that it will be harder to unwrap and verify, that's why I'm asking if there is a more convenient way to write this, something like:
def tighten' (as : Matrix (Fin n) (Fin 2) ℕ) : Matrix (Fin n) (Fin 2) ℕ :=
sorry
-- as.rows ![a,b] -> ![a-b,b-a]
-- as.rows ![a,b] -> if a > b then ![a-b,0] else ![0,b-a]
Any suggestions are welcome!
Bernardo Borges (May 14 2024 at 17:54):
It got some more complicated, since I also need the number of positions that were tightened, with the matrix I get this:
def tighten (as : Matrix (Fin n) (Fin 2) ℕ) : Matrix (Fin n) (Fin 2) ℕ × ℕ :=
(t, ∑i, (as - t) i 0)
where
M := !![1,-1;-1,1]
t := as.map Int.ofNat * M |>.map Int.toNat
theorem Addition
{xs : Fin n → Fin 2}
{as : Matrix (Fin n) (Fin 2) ℕ} {A : ℕ} (ha : PBIneq as xs A)
{bs : Matrix (Fin n) (Fin 2) ℕ} {B : ℕ} (hb : PBIneq bs xs B)
: PBIneq (tighten (as + bs) |>.1) xs ((A + B) - (tighten (as+bs)).2) := by
sorry
Bernardo Borges (May 14 2024 at 18:06):
Then the description of the tighten
function should be:
Given a N by 2 Matrix as, return a tuple, where
1. Is another matrix, where each row follows
def eq : ℕ × ℕ → ℕ × ℕ
| (a,b) => if a > b then (a-b,0) else (0,b-a)
Agains each row of as.
2. A natural number, the sum of all removed lines, where for a single row it is
def rem : ℕ × ℕ → ℕ
| (a,b) => min a b
Bernardo Borges (May 14 2024 at 18:21):
To be yet more specific, I would like to use a notation like this:
def tighten' (as : Matrix (Fin n) (Fin 2) ℤ) := -- : Matrix (Fin n) (Fin 2) ℕ × ℕ :=
∑i:Fin n,
![if as i 0 > as i 1 then as i 0 - as i 1 else as i 1 - as i 0,
min (as i 0) (as i 1)]
But I don't want the \sum operator, because I need the matrix back, I just need to access the rows and transform them somehow.
Bernardo Borges (May 14 2024 at 18:21):
And also an alias to as i 0
and as i 1
would make it more readable.
Bernardo Borges (May 14 2024 at 18:22):
Matrix.map will apply to each element, which is not what I need.
Bernardo Borges (May 14 2024 at 18:40):
Matrix.updateRow Looks promissing but i need to gather the rows of A
first
Bernardo Borges (May 15 2024 at 13:26):
Apparently we can just use a function as a matrix definition:
def tighten'' (as : Matrix (Fin n) (Fin 2) ℕ) : Matrix (Fin n) (Fin 2) ℕ :=
λ i : Fin n =>
let x := as i 0
let y := as i 1
if x > y then
![x - y,0]
else
![0,y - x]
Damiano Testa (May 15 2024 at 13:43):
Everything in Lean is a function.
Eric Wieser (May 15 2024 at 13:52):
You shouldn't do that without prepending Matrix.of
Bernardo Borges (May 15 2024 at 13:52):
Care to explain why, please?
Bernardo Borges (May 15 2024 at 13:54):
For all I know the type assertion of the def
will take care of instances, won't it?
Johan Commelin (May 15 2024 at 13:55):
simp
will thank you :wink:
Bernardo Borges (May 15 2024 at 14:09):
Ok! It's looking more promising. Last thing, is there such a thing as a pattern match for finvec, like a list does? It'd be interesting to get elements like:
def tighten (as : Matrix (Fin n) (Fin 2) ℕ) : Matrix (Fin n) (Fin 2) ℕ :=
Matrix.of λ i : Fin n =>
let ![x,y] := as i
if x > y then
![x - y,0]
else
![0,y - x]
Brendan Seamas Murphy (May 15 2024 at 16:58):
Sort of. You can use Fin.consInduction
and Fin.consCases
to mimick this, but it won't look like pattern matching unless you do induction as i using Fin.consInduction with
or cases as i using Fin.consInduction with
inside tactic mode
Brendan Seamas Murphy (May 15 2024 at 16:58):
Short answer no
Eric Wieser (May 15 2024 at 18:23):
What you have looks optimal
Eric Wieser (May 15 2024 at 18:24):
Are you later doing multiplication with these matrices?
Eric Wieser (May 15 2024 at 18:24):
If not, then maybe you should be working with Fin n -> ℕ \times ℕ
instead
Bernardo Borges (May 15 2024 at 19:09):
Eric Wieser said:
If not, then maybe you should be working with
Fin n -> ℕ \times ℕ
instead
I will multiply with a scalar among other operations. Why is it better to use a tuple?
Eric Wieser (May 15 2024 at 19:13):
If you never do matrix multiplication, then Matrix
is probably getting in your way. Scalar multiplication works fine on tuples.
Eric Wieser (May 15 2024 at 19:14):
Why is it better to use a tuple?
For one, the (x, y)
pattern-matching syntax will work
Bernardo Borges (May 17 2024 at 12:36):
So, if I use a tuple how can this operation be done:
def ceildiv (c : ℕ) (a : ℕ) := (a+c-1) / c
def ApplyCeildiv
(M : Matrix (Fin n) (Fin 2) ℕ)
(c : ℕ)
: Matrix (Fin n) (Fin 2) ℕ :=
M.map (ceildiv c)
Bernardo Borges (May 17 2024 at 12:37):
I'll need to map over matrix and tuple, right?
Last updated: May 02 2025 at 03:31 UTC