Julia: boolean comparisons with arrays - julia

I have a simple question about boolean comparisons in Julia. How do I translate the following Matlab code to Julia?
Matlab:
% create parameters
o = -3;
mat = [65 -4; 65 -3; 65 -2]
% determine which rows of matrix have column 2 less than o AND column 1 equal to 65.
result = (o < mat(:,2) & mat(:,1) == 65)
I've tried the following in Julia:
# create parameters
o = -3
mat = zeros(3,2)
mat[:,1] = 65
mat[1,2] = -4
mat[2,2] = -3
mat[3,2] = -2
mat
# attempt to create desired result
o .< mat[:,2] # this part works
mat[:,1] .== 65 # this part works
test = (o .< mat[:,2] && mat[:,1] .== 65) # doesn't work
test = (o .< mat[:,2] .& mat[:,1] .== 65) # doesn't work
test = (o .< mat[:,2] & mat[:,1] .== 65) # doesn't work

It's a matter of operator precedence. & has a higher precedence in Julia than it does in Matlab. Just shift around your parentheses:
test = (o .< mat[:,2]) .& (mat[:,1] .== 65)
See Noteworthy differences from Matlab in the manual for more details (and it's worth reading through the other differences, too).

Note that you can use the same array creation syntax in Julia:
julia> mat = [65 -4; 65 -3; 65 -2]
3x2 Array{Int64,2}:
65 -4
65 -3
65 -2
You can also use find to get a list of the resulting indices:
o = -3
test = (o .< mat[:,2]) & (mat[:,1] .== 65)
julia> find(test)
1-element Array{Int64,1}:
3

Related

Calculation of quadratic form using broadcasting in Julia

I want to calculate a vector of a quadratic form, extracting the submatrix from 3 by 3 by 5 arrays. However, I cannot make the quadratic form using broadcasting (i.e., macro "#."). When using “for” statement, we can calculate the vector of the quadratic form. I have no idea how to conduct matrix operations using “#.” (I am reluctant to expand the quadratic form to calculate the vector.)
By contrast, the inner product is computable using “#.”.
The example code is as follows:
using LinearAlgebra
a1=[5 7 2; 2 1 5; 6 2 3]
a2=[2 7 1; 3 7 2; 1 2 3]
a3=[8 5 9; 1 1 3; 2 2 3]
a4=[2 5 6; 3 5 1; 1 1 1]
a5=[7 8 1; 5 1 3; 1 5 2]
z=cat(a1,a2,a3,a4,a5,dims=3)
##### case of inner product
x=zeros(5,3)
wz = reshape([],0)
for k in 1:5
w = hcat(z[[1],[1],k], z[2,2,k]) * hcat(z[[1],[1],k], z[[2],[2],k])'
#println(w)
wz=vcat(wz, w)
end
#. wz=convert(Float64,wz)
wz=Matrix{Float64}(wz)
x[:,3]=wz
# [inner product] same result, the 3rd column vector [26.0, 53.0, 65.0, 29.0, 50.0]
display(x)
x=zeros(5,3)
#. x[:,3] = dot(hcat(z[1,1,:],z[2,2,:]), hcat(z[1,1,:],z[2,2,:])) # ok, working
# [inner product] same result, the 3rd column vector [26.0, 53.0, 65.0, 29.0, 50.0]
display(x)
##### case of quadratic form
x=zeros(5,3)
wy = reshape([],0)
for k in 1:5
w = hcat(z[[1],[1],k], z[[2],[2],k]) * z[[1,3],[1,3],k] * hcat(z[[1],[1],k], z[[2],[2],k])'
#println(w)
wy=vcat(wy, w)
end
#. wy=convert(Float64,wy)
wy=Matrix{Float64}(wy)
x[:,3]=wy
# [quadratic form] distinct result, the 3rd column vector [168.0, 183.0, 603.0, 103.0, 359.0]
display(x)
# generating five 2 by 2 matrices, distinct result
#. dot(hcat(z[[1],[1],:],z[[2],[2],:]), z[[1,3],[1,3],:], hcat(z[[1],[1],:],z[[2],[2],:]))
# obtaining ERROR: DimensionMismatch("arrays could not be broadcast to a common size; got a dimension with lengths 2 and 5")
#. dot(hcat(z[1,1,:],z[2,2,:]), z[[1,3],[1,3],:], hcat(z[1,1,:],z[2,2,:]))
Would you mind giving helps and suggestions how to get the calculation of 3rd column vector [168.0, 183.0, 603.0, 103.0, 359.0] (which is made from the quadratic form) in the above code using "#."?
EDIT:
Perhaps the question is about specifically how to make broadcasting work in this case. If so:
#views dot.(vcat.(z[1,1,:],z[2,2,:]),getindex.(Ref(z),Ref([1,3]),Ref([1,3]),axes(z,3)),vcat.(z[1,1,:],z[2,2,:]))
should be a possible clarification. Or with the #. macro (though it doesn't seem simpler):
#. dot(vcat(z[1,1,:],z[2,2,:]),getindex($Ref(z),$Ref([1,3]),$Ref([1,3]),$axes(z,3)),vcat(z[1,1,:],z[2,2,:]))
ORIGINAL:
One way to calculate this:
[
[z[1,1,k] z[2,2,k]]*z[[1,3],[1,3],k]*[z[1,1,k] z[2,2,k]]' |> first
for k ∈ axes(z,3)
]
giving:
5-element Vector{Int64}:
168
183
603
103
359
(the |> first turns 1x1 matrix into scalar)
Option 2:
[let t = z[[1,3],[1,3],k] ; sum(z[i,i,k]*t[i,j]*z[j,j,k] for i ∈ (1,2), j ∈ (1,2)) ; end for k ∈ 1:5]
or:
[let t = z[[1,3],[1,3],k], v = [z[1,1,k],z[2,2,k]] ; dot(v,t,v) ; end for k ∈ 1:5]
or (this is pretty cool):
map((z;t=z[[1,3],[1,3]],v=[z[1,1],z[2,2]])->dot(v,t,v), eachslice(z,dims=3))

User-defined (nonlinear) objective with vectorized variables in JuMP

Is it possible to use vectorized variables with user-defined objective functions in JuMP for Julia? Like so,
model = Model(GLPK.Optimizer)
A = [
1 1 9 5
3 5 0 8
2 0 6 13
]
b = [7; 3; 5]
c = [1; 3; 5; 2]
#variable(model, x[1:4] >= 0)
#constraint(model, A * x .== b)
# dummy functions, could be nonlinear hypothetically
identity(x) = x
C(x, c) = c' * x
register(model, :identity, 1, identity; autodiff = true)
register(model, :C, 2, C; autodiff = true)
#NLobjective(model, Min, C(identity(x), c))
This throws the error,
ERROR: Unexpected array VariableRef[x[1], x[2], x[3], x[4]] in nonlinear expression. Nonlinear expressions may contain only scalar expression.
Which sounds like no. Is there a workaround to this? I believe scipy.optimize.minimize is capable of optimizing user-defined objectives with vectorized variables?
No, you cannot pass vector arguments to user-defined functions.
Documentation: https://jump.dev/JuMP.jl/stable/manual/nlp/#User-defined-functions-with-vector-inputs
Issue you opened: https://github.com/jump-dev/JuMP.jl/issues/2854
The following is preferable to Prezemyslaw's answer. His suggestion to wrap things in an #expression won't work if the functions are more complicated.
using JuMP, Ipopt
model = Model(Ipopt.Optimizer)
A = [
1 1 9 5
3 5 0 8
2 0 6 13
]
b = [7; 3; 5]
c = [1; 3; 5; 2]
#variable(model, x[1:4] >= 0)
#constraint(model, A * x .== b)
# dummy functions, could be nonlinear hypothetically
identity(x) = x
C(x, c) = c' * x
my_objective(x...) = C(identitiy(collect(x)), c)
register(model, :my_objective, length(x), my_objective; autodiff = true)
#NLobjective(model, Min, my_objective(x...))
Firstly, use optimizer that supports nonlinear models. GLPK does not. Try Ipopt:
using Ipopt
model = Model(Ipopt.Optimizer)
Secondly, JuMP documentation reads (see https://jump.dev/JuMP.jl/stable/manual/nlp/#Syntax-notes):
The syntax accepted in nonlinear macros is more restricted than the syntax for linear and quadratic macros. (...) all expressions must be simple scalar operations. You cannot use dot, matrix-vector products, vector slices, etc.
you need wrap the goal function
#expression(model, expr, C(identity(x), c))
Now you can do:
#NLobjective(model, Min, expr)
To show that it works I solve the model:
julia> optimize!(model)
This is Ipopt version 3.14.4, running with linear solver MUMPS 5.4.1.
...
Total seconds in IPOPT = 0.165
EXIT: Optimal Solution Found.
julia> value.(x)
4-element Vector{Float64}:
0.42307697548737005
0.3461538282496562
0.6923076931757742
-8.46379887234798e-9

Filtering using conditional evaluation (&&)

I am having trouble filtering a simple array-based on two conditions. For example, to filter out values between 3 and 5, I tried the following but I get an ERROR: TypeError: non-boolean (BitArray{1}) used in boolean context error.
arr = Array{Int64}([1,2,3,4,5,6])
arr[(arr .> 3) && (arr.< 5)]
Any idea how to solve it?
Also on a side note, I am wondering if there is a function opposite to isless. Something to find a value greater than a certain value.
Here are two ways to do it:
julia> arr = [1,2,3,4,5,6]
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> arr[(arr .> 3) .& (arr.< 5)]
1-element Array{Int64,1}:
4
julia> filter(v -> 3 < v < 5, arr)
1-element Array{Int64,1}:
4
(I personally prefer filter).
To get the opposite of isless just reverse its arguments, or if needed define a new function:
isgreater(x, y) = isless(y, x)
I prefer a set comparison approach because it's quite intuitive:
julia> arr = Array{Int64}([1,2,3,4,5,6])
julia> intersect( arr[ arr .> 1 ], arr[ arr .< 4 ] )
2-element Array{Int64,1}:
2
3
Or list comprehension:
[ x for x in arr if 3 < x < 5]
# or
[ x for x in arr if 3 < x && x < 5]
Also to define an array literal with specific type Int64, there is a dedicated syntax to make it simpler:
arr = Int64[1,2,3,4,5,6]

Returned array is unexpected

The following lines
s = [1 2 5 7 3 3]
index=findall(x -> (x < 7 & x > 3), s)
[idx[2] for idx in index]
returns
0-element Array{Int64,1}
when there is a 5 in s. What is going wrong here?
& is bit-wise AND operator and the operator precedence kicks in here. The logical AND operator in Julia is &&.
You can use parenthesis to make your expression correct for your purpose, i.e. (x > 7) & (x > 3), though I would not recommend this one.
You should instead use logical AND operator &&, or perhaps better directly write what you would write on a paper i.e. 3 < x < 7. All of these methods work.
s = [1 2 5 7 3 3]
index=findall(x -> 3 < x < 7, s)
[idx[2] for idx in index]
& operates on bits and the logical and is &&.
For what you want to do just use filter:
julia> filter(x -> 7 > x > 3, s)
1-element Array{Int64,1}:
5

Testing divisibility of Ints by 11

I'm struggling with this code right now. I want to determine whether an integer is divsible by 11. From what I have read, an integer is divisible to 11 when the sum (one time +, one time -) of its digits is divisible by 11.
For example: 56518 is divisible by 11, because 8-1+5-6+5 = 11, and 11 is divisible by 11.
How can i write this down in Haskell? Thanks in advance.
A number x is divisible by y if it's remainder when divided by y is 0. So you can just do
divisibleBy11 x = x `rem` 11 == 0
ifan I'm sure you know that in real life you would use mod or rem for this simple example, but the algorithm you are asking about is interesting. Here's a fun way to do it that emphasizes the functional nature of Haskell:
digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)
divisible11 = (== 0) . head . dropWhile (>= 11) . iterate (reduce11 . digits)
where
reduce11 [] = 0
reduce11 (d:ds) = foldl combine d $ zip (cycle [(-), (+)]) ds
combine d (op, d') = d `op` d'
Surely, div and mod are faster, but why not? I assume the problem is converting a number to a list of digits:
toDigits = map (read . (:[])) . show
56518 is converted to a String "56518", and each symbol in the string (every digit) is converted to a string itself with map (:[]), at this point we have ["5","6","5","1","8"], and we read every single-digit string as an integer value: [5,6,5,1,8]. Done.
Now we can calculate the sum of digits this way:
sumDigits x = sum (zipWith (*) (cycle [1,-1]) (reverse (toDigits x)))
cycle [1,-1] makes an infinite list [1, -1, 1, -1, ...], which we pair with the reversed list of digits (toDigit x), and multiply elements of every pair. So we have [8, -1, 5, -6, 5] and its sum.
Now we can do it recursively:
isDivisible x
| x == 11 || x == 0 = True
| x < 11 = False
| x > 11 = isDivisible (sumDigits x)
How about...
mod11 n | n < 0 = 11 - mod11 (-n)
| n < 11 = n
| otherwise = mod11 $ (n `mod` 10) - (n `div` 10)

Resources