What functions work with JuMPArrays? - julia

Is there a way to make certain functions such as isinteger() work with JuMPArrays?
I am using Julia/JuMP to solve an optimization problem, and after I get the solution, I want to check if the solution is integer. So here is what I wrote:
#defVar(m, 0<= x[1:3] <= 1)
...
xstar = getValue(x)
if isinteger(xstar)
...
end
And I get an error saying isinteger() has no method matching isinteger(::JuMPArray).
Thanks

So in general you can get an underlying array from a JuMPArray by using [:], e.g.
m = Model()
#variable(m, 0 <= x[1:3] <= 1)
#variable(m, 0 <= y[1:10, 1:10] <= 1)
solve(m)
xstar = getvalue(x)[:]
ystar = getvalue(y)[:,:]
Note that the reason for this is that JuMPArrays don't have to start with index 1, so the user needs to explicitly say they want a normal Julia array before doing things.
Regardless, you shouldn't use isinteger. Solvers don't always return very precise answers, e.g. they might say x[1] = 0.999996 but they really mean it is 1. You should do something like
for i in 1:3
if getvalue(x[i]) >= 0.999
println("x[$i] is 1!")
elseif getvalue(x[i]) <= 0.001
println("x[$i] is 0!")
end
end
to make sure you don't get any false negatives. If the variable is restricted to be integer or binary, use iround, e.g.
for i in 1:3
v = iround(getvalue(x[i]))
if v == 1
println("x[$i] is 1!")
elseif v == 0
println("x[$i] is 0!")
end
end
but it looks like in this case you are just seeing if the solution is naturally 0 or 1.

Related

Check multiple conditions on the same function output in Julia

Is there a way to check multiple Boolean conditions against a value (to achieve the same as below) without computing sum twice or saving the result to a variable?
if sum(x) == 1 || sum(x) > 3
# Do Something
end
You can use one of several options:
Anonymous function:
if (i->i>3||i==1)(sum(x))
# Do Something
end
Or,
if sum(x) |> i->i>3||i==1
# Do Something
end
DeMorgan's theorem:
if !(3 >= sum(x) != 1)
# Do Something
end
And if used inside a loop:
3 >= sum(x) != 1 && break
# Do Something
or as function return:
3 >= sum(x) != 1 && return false
But using a temporary variable would be the most readable of all:
s = sum(x)
if s > 3 || s == 1
# Do Something
end
Syntactically, a let is valid in that position, and the closest equivalent to AboAmmar's variant with a lambda:
if let s = sum(x)
s == 1 || s > 3
end
# do something
end
I'd consider this rather unidiomatic, though.

sum function in Julia is giving error if the array is empty

I am trying to create a code which identifies if the elements in an array are monotonic or not.
I wrote the below code and got the error -
function isMonotonic(array)
if length(array) <= 2
return true
end
check_up = []
check_down = []
for i in range(2, length(array))
if array[i] <= array[i-1]
append!(check_up, 1)
end
if array[i] >= array[i - 1]
append!(check_down, 1)
end
end
if sum(check_up) == length(array) - 1 || sum(check_down) == length(array) - 1
return true
else
return false
end
end
isMonotonic([1, 2, 3, 4, 5, 6 , 7])
I am getting the below error
Error: Methoderror: no method matching zero(::Type{Any})
I think it is because I am trying to sum up the empth array, I want to understand how to overcome this problem in general, I have a solution for the above code, but in genral I want to know the reason and how to use it. I do not want to first check if the array is empty or not and then do the sum.
If you wanted to save yourself lots of effort, the simplest solution would just be:
my_ismonotonic(x) = issorted(x) || issorted(x ; rev=true)
This will return true if x is sorted either forwards, or in reverse, and false otherwise.
We could maybe make it a little more efficient using a check so we only need a single call to issorted.
function my_ismonotonic(x)
length(x) <= 2 && return true
for n = 2:length(x)
if x[n] > x[1]
return issorted(x)
elseif x[n] < x[1]
return issorted(x ; rev=true)
end
end
return true
end
# Alternatively, a neater version using findfirst
function my_ismonotonic(x)
length(x) <= 2 && return true
ii = findfirst(a -> a != x[1], x)
isnothing(ii) && return true # All elements in x are equal
if x[ii] > x[1]
return issorted(x)
else
return issorted(x ; rev=true)
end
end
The loop detects the first occurrence of an element greater than or less than the first element and then calls the appropriate issorted as soon as this occurs. If all elements in the array are equal then the loop runs over the whole array and returns true.
There are a few problems of efficiency in your approach, but the reason you are getting an actual error message is because given the input, either this expression sum(check_up) or this expression sum(check_down) will effectively result in the following call:
sum(Any[])
There is no obvious return value for this since the array could have any type, so instead you get an error. If you had used the following earlier in your function:
check_up = Int[]
check_down = Int[]
then you shouldn't have the same problem, because:
julia> sum(Int[])
0
Note also that append! is usually for appending a vector to a vector. If you just want to add a single element to a vector use push!.

looping over an array and checking its elements

I have an array 'A'. I want to do a loop over all the elements of A, checking to see if any are greater than or equal to 1. If they are, I would like to assign a '1' to a new array 'B' in the same element index of A.
How would I go about implementing this?
I have the cumbersome idea of:
for i in 1:end
for j in 1:end
if A[i,j] >= 1
B[i,j] = 1
else
B[i,j] = 0
end
end
end
but I would prefer something more succinct.
Just use broadcast:
B = A .≥ 1
You can certainly use broadcasting as Oscar suggested (e.g. B = A .>= 1), but there's also nothing wrong with loops, since loops are fast and avoid excess allocations. You really only need one loop though, and the if statement is slightly superfluous, so:
B = similar(A, Int64) # If B doesn't already exist, otherwise omit this line
#inbounds for i in eachindex(A)
B[i] = A[i] >= 1
end
The #inbounds is optional, but improves speed.

if a<x<b in matlab

I need any help for Matlab's thinking method.Ithink I can explaine my problem with a simple example better. Let's say that I have a characteristic function x=y+x0, x0's are may starting values.Then I want to define my function in a grid.Then I define a finer grid and I want to ask him if he knows where an arbitrary (x*,y*) is.To determine it mathematically I should ask where the corresponding starting point (x0*) is. If this startig point stay between x(i,1)
clear
%%%%%%%%%%&First grid%%%%%%%%%%%%%%%%%%%%
x0=linspace(0,10,6);
y=linspace(0,5,6);
for i=1:length(x0)
for j=1:length(y)
x(i,j)=y(j)+x0(i);
%%%%%%%%%%%%%%%%%%%Second grid%%%%%%%%%%%%%%%%%%
x0fine=linspace(0,10,10);
yfine=linspace(0,5,10);
for p=1:length(x0fine)
for r=1:length(yfine)
xfine(p,r)=yfine(r)+x0fine(p);
if (x(i,1)<xfine(p,1)')&(x0fine(p,1)'<x(i+1,1))%%%%I probabliy have my first mistake %here
% if y(j)<yfine(r)<y(j+1)
% xint(i,j)=(x(i,j)+x(i,j+1)+x(i+1,j)+x(i+1,j+1))./4;
% else
% xint(i,j)= x(i,j);
%end
end
end
end
end
While a < b < c is legal MATLAB syntax, I doubt that it does what you think it does. It does not check that a < b and b < c. What it does is, it checks whether a < b, returning a logical value (maybe an array of logicals) and then, interpreting this logical as 0 or 1, compares it against c:
>> 2 < 0 < 2
ans =
1
>> 2 < 0 < 1
ans =
1
>> 0 < 0 < 1
ans =
1
First in matlab you should avoid as much as possible to do loops.
For instance you can compute x and xfine, with the following code:
x0=linspace(0,10,6);
y=linspace(0,5,6);
x=bsxfun(#plus,x0',y);
x0fine=linspace(0,10,10);
yfine=linspace(0,5,10);
xfine=bsxfun(#plus,x0fine',yfine);
Then given (X*,y*) your want to fine x0*, in your simple example, you can just do: x0*=x*-y*, I think.

using while loop with logical operators (AND and OR)

n<-NULL
acr<-NULL
while((is.numeric(n)==F) & (acr<0 ¦acr>1)){
print("enter a positive integer and the average cancellation rate you want")
try(n<-scan(what=integer(),nmax=1), silent=TRUE);
try(acr<-scan(what=double(),nmax=1), silent=TRUE)
}
I would want the users of my program to enter a positive integer which I store in "n" and the second
entry which I keep in "acr" is a probability so it lies between 0 and 1.
(I don't want it to be exacly 0 or 1, though it could be according to probability theory).
So I want the user to keep on doing the entry until they are able to enter a positive integer for "n" and a probability value between 0 and 1 for "acr".(using while with the AND, OR operators)
However, I am having a problem with the while statement/loop. I have tried all other possibilities such as the one below, but it still doesn't work.
while(is.numeric(n)==F & acr<0 ¦acr>1)
AGAIN:question 2
There is a problem with what=double() also in the scan function, I think.
I know that, for example, 0.5 is a double data type in other programming languages but
I cannot figure it out in R(I don't know what it is called in R).
what is the difference between integer() and double() in R? (I am not familiar with double)
I would be highly appreciative to anyone who could come to my aid.
many thanks to all.
Isaac Owusu
This following example should work. Please be aware that is.integer()
"does not test if ‘x’ contains
integer numbers! For that, use
‘round’, as in the function
‘is.wholenumber(x)’ in the examples"
(see help(is.integer)).
For that reason, I first define a new function is.wholenumber().
is.wholenumber <- function(x, tol = .Machine$double.eps^0.5){
abs(x - round(x)) < tol
}
n <- NULL
acr <- NULL
stay.in.loop <- TRUE
while(stay.in.loop){
print("Please insert n and acr!")
n <- readline("Insert n: ")
acr <- readline("Insert acr: ")
n <- as.numeric(n)
acr <- as.numeric(acr)
## stay.in.loop is true IF any of the expressions is NOT TRUE
stay.in.loop <- !(is.wholenumber(n) & ((0 < acr) & (acr < 1)))
}
NULL may be a bad initialization here, as its comparison does not give a regular boolean. Since the condition is that n should be positive, try this:
n <- -2
acr <- -2
while((n<=0) | (acr<0) | (acr>1)) {
print("enter a positive integer and the average cancellation rate you want")
try(n<-scan(what=integer(),nmax=1), silent=TRUE);
try(acr<-scan(what=double(),nmax=1), silent=TRUE);
}

Resources