How to iterate over two arrays in parallel - julia

I have two arrays that I want to iterate over at the same time.
I'm using this:
julia> xs = [1,2,3];
julia> ys = [4,5,6];
julia> for i in 1:length(xs)
x = xs[i]
y = ys[i]
#show x, y
end
(x, y) = (1, 4)
(x, y) = (2, 5)
(x, y) = (3, 6)
Is there a better way to iterate over multiple arrays in Julia?

Use zip along with tuple destructuring:
julia> xs = [1,2,3];
julia> ys = [4,5,6];
julia> for (x, y) in zip(xs, ys)
#show x, y
end
(x, y) = (1, 4)
(x, y) = (2, 5)
(x, y) = (3, 6)
zip will stop iteration at the shortest array:
julia> for (x, y) in zip([1,2], [0,0,0])
#show x, y
end
(x, y) = (1, 0)
(x, y) = (2, 0)
This pattern can be generalized to an arbitrary number of lists:
julia> for (x, y, z) in zip([1,2], [3,4], [5,6])
#show x, y, z
end
(x, y, z) = (1, 3, 5)
(x, y, z) = (2, 4, 6)

One possibility consists in using the eachindex function: if it is given multiple Array-like arguments, it will return a iterable set of indices suitable to iterate on all arguments at once.
This is useful in particular in the following situations:
when you need to use the index itself (for example because you don't only need to access the elements of the collections, but also set some of them), or
when you want to check that both arrays indeed have the same number of elements (this might or might not be a desired property depending on your use case).
Example 1: using the index itself to fill the first array with values coming from the second
julia> x = [1,2,3];
julia> y = [4,5,6];
julia> #inbounds for i in eachindex(x, y)
x[i] = 2*y[i]
end
julia> x
3-element Array{Int64,1}:
8
10
12
Example 2: check that the arrays have the same range
julia> x = [1,2];
julia> y = [4,5,6];
julia> #inbounds for i in eachindex(x, y)
x[i] = 2*y[i]
end
ERROR: DimensionMismatch("all inputs to eachindex must have the same indices, got [1, 2] and [1, 2, 3]")
Example 3: note that eachindex generalizes well for multi-dimensional arrays too.
julia> x = zeros(2, 3);
julia> y = ones(2, 3);
julia> #inbounds for i in eachindex(x, y)
x[i] = 2*y[i]
end
julia> x
2×3 Array{Float64,2}:
2.0 2.0 2.0
2.0 2.0 2.0

You can iterate over multiple collections using map and foreach. For example, with map:
julia> x, y = 1:3, 4:6;
julia> map(hypot, x, y)
3-element Array{Float64,1}:
4.123105625617661
5.385164807134504
6.708203932499369
For more complicated multi-line anonymous functions, you can use do-block syntax:
julia> xs, ys = 1:4, 10:10:40;
julia> map(xs, ys) do x, y
if isodd(x)
x + y
else
x * y
end
end
4-element Array{Int64,1}:
11
40
33
160
foreach is very similar to map, but is intended for use when a function is applied for its side effect, like printing or plotting, rather than its return value. An example with foreach:
julia> x, y = ["a", "b", "c"], 1:3;
julia> foreach(println ∘ ^, x, y)
a
bb
ccc
Note the use of the function composition operator in the foreach call.

Related

Symply.py for getting coefficients for ALL combination of the variables of a multivariable polynomial

How to get coefficients for ALL combinations of the variables of a multivariable polynomial using sympy.jl or another Julia package for symbolic computation?
Here is an example from MATLAB,
syms a b y
[cxy, txy] = coeffs(ax^2 + by, [y x], ‘All’)
cxy =
[ 0, 0, b]
[ a, 0, 0]
txy =
[ x^2y, xy, y]
[ x^2, x, 1]
My goal is to get
[ x^2y, xy, y]
[ x^2, x, 1]
instead of [x^2, y]
I asked the same question at
https://github.com/JuliaPy/SymPy.jl/issues/482
and
https://discourse.julialang.org/t/symply-jl-for-getting-coefficients-for-all-combination-of-the-variables-of-a-multivariable-polynomial/89091
but I think I should ask if this can be done using Sympy.py.
Using Julia, I tried the following,
julia> #syms x, y, a, b
julia> ff = sympy.Poly(ax^2 + by, (x,y))
Poly(ax**2 + by, x, y, domain='ZZ[a,b]')
julia> [prod(ff.gens.^i) for i in ff.monoms()]
2-element Vector{Sym}:
x^2
y
This is a longer form rewrite of the one-liner in the comment.
It uses Pipe.jl to write expressions 'functionally', so familiarity with pipe operator (|>) and Pipe.jl will help.
using SymPy
using Pipe
#syms x, y, a, b
ff = sympy.Poly(a*x^2 + b*y, (x,y))
max_degrees =
#pipe ff.monoms() .|> collect |> hcat(_...) |>
reduce(max, _, dims=2) |> vec
degree_iter =
#pipe max_degrees .|> UnitRange(0, _) |>
tuple(_...) |> CartesianIndices
result = [prod(ff.gens.^Tuple(I)) for I in degree_iter] |>
reverse |> eachcol |> collect
or using more of the python methods:
[prod(ff.gens.^I) for
I in Iterators.product((0:d for d in ff.degree.(ff.gens))...)] |>
reverse |> eachcol |> collect
Both give the desired result:
2-element Vector{...}:
[x^2*y, x*y, y]
[x^2, x, 1]
UPDATE:
In case there are more than 2 generators, the result needs to be a Array with higher dimension. The last bits of matrix transposes is immaterial and the expressions become:
Method 1:
max_degrees =
#pipe ff.monoms() .|> collect |> hcat(_...) |>
reduce(max, _, dims=2) |> vec
degree_iter =
#pipe max_degrees .|> UnitRange(0, _) |>
tuple(_...) |> CartesianIndices
result = [prod(ff.gens.^Tuple(I)) for I in degree_iter]
Method 2:
result = [prod(ff.gens.^Tuple(I)) for I in degree_iter]
Thanks a lot #Dan Getz. Your solution works for the TOY example from MATLAB. My real case is more complicated, which has more variables and polynominals. I tried your method for 3 variables,
using SymPy
#syms x, y, z, a, b
ff = sympy.Poly(a*x^2 + b*y + z^2 + x*y + y*z, (x, y, z))
[prod(ff.gens.^Tuple(I)) for I in CartesianIndices(tuple(UnitRange.(0,vec(reduce(max, hcat(collect.(ff.monoms())...), dims=1)))...))]
I got the following error,
ERROR: LoadError: DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 3 and 5
Stacktrace:
How to generate your method to any number of variables with different degrees, e.g., x^3 + y^3 + z^3 + xyz + xy^2z?
You can find the degree of each of the two variables of interest and then use them to create the matrix of generators; you can use them to get the coefficients of interest. I am not sure what you expect if the equation were like a*x**2 + b*y + c...
>>> from sympy import *
>>> from sympy.abc import a, b, x, y
>>> eq = a*x**2 + b*y
>>> deg = lambda x: Poly(eq, x).degree() # helper to give degree in "x"
>>> v = (Matrix([x**i for i in range(deg(x),-1,-1)]
... )*Matrix([y**i for i in range(deg(y),-1,-1)]).T).T; v
Matrix([[x**2*y, x*y, y], [x**2, x, 1]])
>>> Matrix(*v.shape, [eq.coeff(i) if i.free_symbols else eq.as_coeff_Add()[0]
... for i in v])
Matrix([[0, 0, b], [a, 0, 0]])
From #jverzani (thanks)
using SymPy;
#syms a b x y;
eq = a*x^2 + b*y;
deg = x -> sympy.Poly(eq, x).degree();
xs, ys = [x^i for i ∈ range(deg(x):-1:0], [y^i for i ∈ deg(y):-1:0];
v = permutedims(xs .* permutedims(ys));
M = [x^2*y x*y y; x^2 x 1];
[length(free_symbols(i)) > 0 ? eq.coeff(i) : eq.as_coeff_add()[1] for i ∈ v];
[0 0 b; a 0 0]

Recursive function in Julia

Is there a way in Julia to smoothly define a recursive function?
function f(x_0, y_0)
x_1 = g1(x_0,y_0)
y_1 = g2(x_0,y_0)
x_2 = g1(x_1,y_1)
y_2 = g2(x_1,y_1)
x_3 = g1(x_2,y_2)
y_3 = g2(x_2,y_2)
x_4 = g1(x_3,y_3)
y_4 = g2(x_3,y_3)
return x_2,y_2
end
In particular, I want to be able to call the function and give parameter that would specify the circle of the recursion. Something like this:
f(x_0, y_0, circle = 2)
>> x_2, y_2
f(x_0, y_0, circle = 3)
>> x_3, y_3
If you define
function apply_n(f, x_0, cycle_len)
for _ in 1:cycle_len
x_0 = f(x_0)
end
return x0
end
and call apply_n((x,y)->(g1(x,y),g2(x,y)), (x_0,y_0), 3) it will work.
IterTools.jl provides an iterate method that does exatly this.
help?> iterated
…
iterated(f, x)
Iterate over successive applications of f, as in x, f(x), f(f(x)), f(f(f(x))), ...
…
julia> x_0, y_0 = 5, 10;
g1 = +;
g2 = -;
julia> using IterTools: iterated, nth
julia> nth(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 3)
(10, 20)
As the documentation says, the result is (an iterator over) (x, f(x), f(f(x)), …), which means (x_2, y_2) from the question would be f(f(x)) which is the third element - that's why the call to nth above passes 3 as the second argument.
An advantage of this method is that it returns an iterator that you can then treat like any other iterator. So if you instead want the results of all the first 5 stages of the process:
julia> using Base.Iterators: take
julia> take(iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0)), 5) |> collect
10-element Vector{Tuple{Int64, Int64}}:
(5, 10)
(15, -5)
(10, 20)
(30, -10)
(20, 40)
Or only want the recursion to continue while a condition is true:
julia> using Iterators: takewhile
julia> takewhile(((x, y),) -> x + y < 50,
iterated(((x, y),) -> (g1(x, y), g2(x, y)), (x_0, y_0))) |> collect
4-element Vector{Tuple{Int64, Int64}}:
(5, 10)
(15, -5)
(10, 20)
(30, -10)

Julia - Equivalent of python `pop`. Remove elements from array using boolean array and return them

Is there an equivalent to Python's pop? I have an array x and a boolean array flag of the same length. I would like to extract x[flag] and be able to store it in a variable x_flagged while at the same time remove them in place from x.
x = rand(1:5, 100)
flag = x .> 2
x_flagged = some_function!(x, flag) # Now x would be equal to x[x .<= 2]
Try this one using deleteat!
julia> function pop_r!(list, y) t = list[y]; deleteat!( list, y ); t end
julia> x = rand(1:5, 100)
100-element Vector{Int64}
julia> flag = x .> 2
100-element BitVector
julia> pop_r!( x, flag )
60-element Vector{Int64}
julia> x
40-element Vector{Int64}
You can use splice! with a bit of help from findall:
julia> x_flagged = splice!(x, findall(flag))
59-element Vector{Int64}:
...
julia> size(x)
(41,)
splice!(a::Vector, indices, [replacement]) -> items
Remove items at specified indices, and return a collection containing the removed items.

How to get a linsolve solution in matrix form?

Im using SymPy in Julia. My purpose is to solve a homogeneous system of linear equations (Ax=0) with more unknowns than variables (A is not square).
Then, Im using the following code.
using SymPy
x, y, z, w = symbols("x y z w")
M = sympy.Matrix(((9, 2, 1,- 4, 0), (-4, -3, -1, -5, 0)))
s = linsolve(M, (x, y, z, w))
With this code Im able to get the correct solution. However, I´dont known how to manipulate that solution.
The final goal is to be able to get the solution in matrix form as lines representing (x and y) and column (z and w). (since x(z, w) and y(z,w)).
Thanks
If numerical (rather than symbolic) computations are acceptable, then this will get the job done:
julia> using LinearAlgebra
julia> M = rand(2,4)
2×4 Array{Float64,2}:
0.497965 0.704514 0.152799 0.69448
0.594486 0.695488 0.327688 0.710573
julia> Q,R = qr(M);
C = -R[1:2,1:2]\R[1:2,3:4]
xy(zw) = C*zw;
# Check that `[xy(zw); zw]` is indeed in the nullspace of `M`:
julia> zw = rand(2)
M*[xy(zw);zw]
2-element Array{Float64,1}:
-2.7755575615628914e-17
-1.1102230246251565e-16

How to pass keywords and keyword variable values to a function via Tuples

You can easily pass "normal" (i.e. non-keyword) variable values to a function via a Tuple with an ellipsis, like e.g.:
julia> f(x, y, z) = x + y + z;
julia> f(0, 1, 2)
3
julia> varvalues = 0, 1, 2
(0,1,2)
julia> f(varvalues...)
3
But for keyword variables, how do you pass both the keywords and the corresponding variable values via variables? Like e.g. (forgive the silly example):
julia> function g(x, y, z; operation = "add", format = "number")
operation == "add" && format == "number" && return x + y + z
operation == "add" && format == "string" && return string(x + y + z)
operation == "times" && format == "number" && return x * y * z
operation == "times" && format == "string" && return string(x * y * z)
end; # yep, I know this not type-stable
julia> g(0, 1, 2, operation = "times", format = "string")
"0"
julia> g(varvalues..., operation = "times", format = "string") # varvalues = (0,1,2)
"0"
So I would like to define two variables, analogous to varvalues above: keywords with the keywords and keywordvarvalues with the corresponding variable values, that can be passed to function g. Something like this, but that works:
julia> keywords = :operation, :format
(:operation,:format)
julia> keywordvarvalues = "times", "string"
("times","string")
julia> g(varvalues..., keywords... = keywordvarvalues...)
ERROR: MethodError: no method matching broadcast!...
I suppose I can always compose this String from keywords and keywordvarvalues:
expressionstring = """g(varvalues..., operation = "times", format = "string")"""
and then parse-eval it, but that's prolly bad practice, no?
This works:
julia> keywords = :operation, :format
(:operation,:format)
julia> keywordvarvalues = 10, 20
(10,20)
julia> g(; operation=1, format=2) = (operation, format)
g (generic function with 1 method)
julia> g(; zip(keywords, keywordvarvalues)...)
(10,20)
You can also use dictionaries:
julia> g(; keywords...) = keywords
julia> g(a=3, b=4)
2-element Array{Any,1}:
(:a,3)
(:b,4)
julia> d = Dict(:c=>5, :d=>6)
Dict{Symbol,Int64} with 2 entries:
:c => 5
:d => 6
julia> g(; d...)
2-element Array{Any,1}:
(:c,5)
(:d,6)

Resources