Einops rearrange function basic functionallity - torch

I'm trying to grok the einops syntax for tensor reordering, but am somehow missing the point
If I have the following matrix:
mat = torch.randint(1, 10, (8,4))
I understand what the following command does:
rearrange(mat, '(h n) w -> (n h) w', n = 2)
But can't really wrap my head around the following ones:
rearrange(mat, '(n h) w -> (h n) w', n = 2)
rearrange(mat, '(n h) w -> (h n) w', n = 4)
Any help would be appreciated

rearrange(mat, '(h n) w -> (n h) w', n = 2)
and
rearrange(mat, '(n h) w -> (h n) w', n = 2)
are inversions of each other. If you can imagine what one does, second makes reverse transform
As for the latter, mat is 8x4
rearrange(mat, '(n h) w -> (h n) w', n = 4)
So you first split first dimension in 4x2 (below I ignore w dimension, because nothing special happens with it)
[0, 1, 2, 3, 4, 5, 6, 7]
to
[0, 1,
2, 3,
4, 5,
6, 7]
then you change order of axes to 2x4 (transpose)
[0, 2, 4, 6,
1, 3, 5, 7]
then merge two dimensions into one
[0, 2, 4, 5, 1, 3, 5, 7]
If you still don't feel how that works, take simpler examples like
rearrange(np.arange(50), '(h n) -> h n', h=5)
rearrange(np.arange(50), '(h n) -> h n', h=10)
rearrange(np.arange(50), '(h n) -> n h', h=10)
etc. So that you could track movement of each element in the matrix

Related

How can I compare the average of a list with every element in the same list?

fun promedio l = let
fun sl(nil, sum, len) = sum div len
| sl(h::t, sum, len) = sl(t, sum + h, len + 1)
in
sl(l, 0, 0)
end;
This code gives me the average of an list, but now I have to compare every element in that list with the average and say how many elements are greater than the average and how many are lower than the average.
Could you please help me with this last step?
Your promedio function fails on the empty input; promedio [], since it tries to divide by zero.
Here are two alternative ways to write this that takes empty lists into account:
(* Using one traversal *)
fun average xs =
case foldl (fn (x, (sum, count)) => (x + sum, 1 + count)) (0, 0) xs of
(0, 0) => 0
| (x, y) => x div y
(* Using two traversals *)
val sum = foldl op+ 0
fun average [] = 0
| average xs = (sum xs) div (length xs)
You can partition a list using any predicate with List.partition.
In your case, the predicate may be x <= avg.
fun partition_average xs =
let val avg = average xs
in List.partition (fn x => x <= avg) xs end
Notice that if I didn't bind average xs to avg outside the fn x => ...,
(* Don't do this *)
fun partition_average xs =
List.partition (fn x => x <= average xs) xs
then I'd be recomputing average xs for each element of xs.
A demo:
- partition_average [1,2,3,4,5]; (* avg being 3 *)
> val it = ([1, 2, 3], [4, 5]) : int list * int list
- partition_average [1,2,3,9]; (* avg being 3(.75) *)
> val it = ([1, 2, 3], [9]) : int list * int list

How to complete this proof of commutativity with `replace`?

On this documentation, it is mentioned how replace could be used to complete the proof, but it ends up using rewrite, which seems to be a syntax sugar that writes replace for you. I'm interested in understanding how to use it explicitly.
If I understand correctly, it could be used to rewrite S k = S (plus k 0) as S (plus k 0) = S (plus k 0), given a proof that k = plus k 0, which would then be provable by reflexivity. But if we instance it as replace {P = \x => S x = S (plus k 0)} {x = k} {y = plus k 0} rec, we'll now need a proof of S k = S (plus k 0), which is what we wanted to prove to begin with. In short, I'm not sure what exactly P should be.
Ah, it is fairly obvious in retrospect. If we let:
P = \x => S x = S (plus k 0)
Then, we can prove it for x = (plus k 0) (by reflexivity). Now, if we let y = k, then, by using replace, we gain a proof of S k = S (plus k 0), which is what we need. Or, in other words:
plusCommZ : (m : Nat) -> m = plus m 0
plusCommZ Z = Refl
plusCommZ (S k) = replace
{P = \x => S x = S (plus k 0)}
{x = plus k 0}
{y = k}
(sym (plusCommZ k))
Refl
Completes the proof. We could do it the other way around with P = \x => S x = S k.

How can I efficiently prove existential propositions with multiple variables in Isabelle/Isar?

Say I want to prove the lemma ∃ n m k . [n, m, k] = [2, 3, 5] in Isabelle/Isar. If I go ahead as suggested in the Isabelle/HOL tutorial on page 45, my proof looks as follows:
lemma "∃ n m k . [n, m, k] = [2, 3, 5]"
proof
show "∃ m k . [2, m, k] = [2, 3, 5]"
proof
show "∃ k . [2, 3, k] = [2, 3, 5]"
proof
show "[2, 3, 5] = [2, 3, 5]" by simp
qed
qed
qed
Of course, this is way too verbose. How can I prove propositions like the above one such that the proofs are concise and readable?
Multiple existential quantifiers can be introduced in a single step by applying the single-quantifier introduction rule several times. For example, the proof method (rule exI)+ introduces all outermost existential quantifiers.
lemma "∃n m k. [n, m, k] = [2, 3, 5]"
proof(rule exI)+
show "[2, 3, 5] = [2, 3, 5]" by simp
qed
Alternatively, you can first state the instantiated property and then use an automatic proof method to do the instantiations. Usually blast works well here because it does not invoke the simplfier. In your example, you will have to add type annotations because numbers are overloaded.
lemma "∃n m k :: nat. [n, m, k] = [2, 3, 5]"
proof -
have "[2, 3, 5 :: nat] = [2, 3, 5]" by simp
then show ?thesis by blast
qed

How to create a function that encodes run-length using fold_right?

I created a function and helper function that find the number of repeating elements in a list, and what those elements.
let rec _encode l x =
match l with
| [] -> 0
| head::rest -> (if head = x then 1 else 0) + encode rest x
let encode l x = ((_encode l x), x)
In this case, I have to specify what that element is for it to search.
So this is a two part question. 1) How do I do it to return a list of tuples, with format (int * 'a) list, where int is the # of rep, and 'a is the element that is repeating.
2) How would I implement this using fold_right?
I was thinking something along the lines of:
let encode (l : 'a list) : (int * 'a) list = fold_right (fun (x,hd) lst ->
match x with
| [] -> 0
| hd :: rest -> if hd x then (x+1, hd) else (x, hd)) l []
Your attempt looks very confused:
It doesn't use lst, hd (the first one), or rest.
x is used as a list (match x with []) and a number (x+1).
The elements of x (list) are functions that return bools?? (... hd::rest -> ... if hd x)
The function sometimes returns a number (0) and sometimes a tuple ((x, hd)).
Here's how I'd do it:
let encode l =
let f x = function
| (n, y) :: zs when x = y -> (n + 1, y) :: zs
| zs -> (1, x) :: zs
in
fold_right f l []
Which is the same as:
let encode l =
let f x z = match z with
| (n, y) :: zs when x = y -> (n + 1, y) :: zs
| zs -> (1, x) :: zs
in
fold_right f l []
Which is the same as:
let encode l =
fold_right (fun x z ->
match z with
| (n, y) :: zs when x = y -> (n + 1, y) :: zs
| zs -> (1, x) :: zs
) l []

How to do an addition on a list with a condition?

I have a university course about functional programming, where I use SML. As a preparation for the exam, I am working on some of the older exam sets without solutions.
One of the only questions I really have problems with is the following question using foldl:
Consider the program skeleton: fun
addGt k xs = List.foldl (...) ... xs;
Fill in the two missing pieces
(represented by the dots ...), so that
addGt k xs is the sum of those
elements in xs, which are greater than
k. For example, addGt 4 [1, 5, 2, 7,
4, 8] = 5 + 7 + 8 = 20
I am sure this is really easy, but I have a very hard time understanding the foldl and foldr functions.
What I have now is the following (which seems to be very wrong if you ask my compiler!):
fun addGt(k,xs) = List.foldl ( fn x => if x > k then op+ else 0) 0 xs;
I would really appreciate some help with this question, and maybe a very short comment which would cast some light on the foldl and foldr functions!
A solution that I just though of is the following:
fun addGt(k, xs) = List.foldl (fn (x, y) => if x >= 5 then x + y else y) 0 xs;
But let me explain. First of all check the type of the List.foldl function, it's:
('a * 'b -> 'b) -> 'b -> 'a list -> 'b
So List.foldl is a curried function that takes as first parameter another function of type ('a * 'b -> 'b). You used (fn x => if x > k then op+ else 0) which has type int -> int. You should instead provide List.foldl with a function that takes a tuple of type int * int and returns an int, so something like this: (fn (x, y) => do stuff). That's why your code didn't compile, you passed a wrong type of function in foldl.
Now you can think of foldl this way:
foldl f b [x_1, x_2, ..., x_(n - 1), x_n] = f(x_n, f(x_(n - 1), ..., f(x2, f(x1, b)) ...)) where f is a function of type ('a * 'b -> 'b), b is something of type 'b and the list [x_1, x_2, ..., x_(n - 1), x_n] is of type 'a list.
And similar for foldr you can think it in this way:
foldr f b [x_1, x_2, ..., x_(n - 1), x_n] = f(x_1, f(x_2, ..., f(x_(n - 1), f(x_ n, b))
If you call foldl f s ls on a list, ls = [x1, x2, ..., xn], then you get the result:
f(xn, ... f(x2, f(x1, s)))
That is, it starts by finding
a1 = f(x1, s)
Then
a2 = f(x2, a1)
and so on, until it's through the list.
When it's done, it returns an.
You can think of the a-values as being a sort of accumulator, that is, ai is the result as it would be if the list was only [x1, x2, ..., xi] (or rather, the first i elements of the list).
Your function will usually have the form:
fn (x, a) => ...
What you then need to do is think: Okay, if I have the next element in the list, x(i+1), and the value ai, which is the result for the list [x1, x2, ..., xi], what do I need to do to find the value a(i+1), which is the result for the list [x1, x2, ..., xi, x(i+1)].
s can be thought of as the value given to the empty list.
foldr works the same way, only you start from the back of the list instead of from the front.

Resources