Summing columns of an array in model constraint in Julia - arrays

Consider the following optimisation model:
I = 1:5; J = 1:5; K = 1:5;
m = Model(HiGHS.Optimizer)
#variable(m, A[i in I, j in J, k in K] >= 0)
#variable(m, y[i in I, k in K] >= 0)
#constraint(m, sum(collect(A[:,:,1]),dims = 2) .== y[:,1])
In the model, I have a 5x5x5 array variable A, and a 5x5 array variable y. I want to have an equation constraint, where the vector obtained by adding the column vectors of the matrix A[:,:,1] together is (entry-wise) equal to the column vector p[:,1].
However, the above code gives an error:
MethodError: no method matching _broadcasted_type(::Base.Broadcast.ArrayStyle{JuMP.Containers.DenseAxisArray}, ::Base.HasShape{2}, ::Type{AffExpr})
How can I fix that?

Apply collect to the other side of the equation:
julia> #constraint(m, vec(sum(collect(A[:,:,1]),dims = 2)) .== collect(y[:,1]))
5-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
A[1,1,1] + A[1,2,1] + A[1,3,1] + A[1,4,1] + A[1,5,1] - y[1,1] == 0.0
A[2,1,1] + A[2,2,1] + A[2,3,1] + A[2,4,1] + A[2,5,1] - y[2,1] == 0.0
....
EDIT
note that your JuMP experience will be much more enjoyable if you do:
I = 5; J = 5; K = 5;
#variable(m, A[1:I, 1:J, 1:K] >= 0)
#variable(m, y[1:I, 1:K] >= 0)
Now you do not have dense arrays and can do what you initially wanted:
julia> #constraint(m, sum(A[:,:,1],dims = 2) .== y[:,1])
5×1 Matrix{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
A[1,1,1] + A[1,2,1] + A[1,3,1] + A[1,4,1] + A[1,5,1] - y[1,1] == 0.0
A[2,1,1] + A[2,2,1] + A[2,3,1] + A[2,4,1] + A[2,5,1] - y[2,1] == 0.0
...

Related

Summing columns of an array in Julia gives an error

In my Julia optimisation model, I have a variable A which is a 5x5x5 array. Then A[:,:,1] is a matrix. In my model, I wish to calculate the sum of the column vectors of A[:,:,1]. Here is my code:
I = 1:5; J = 1:5; K = 1:5;
m = Model(HiGHS.Optimizer)
#variable(m, A[i in I, j in J, t in K] >= 0)
sum(A[:,:,1],dims = 2)
However, this gives me an error:
No method is implemented for reducing index range of type UnitRange{Int64}. Please implement reduced_index for this index type or report this as an issue.
How can I fix this error? The code works if I write
#variable(m, A[i in 1:5, j in 1:5, t in 1:5] >= 0)
but in my model, the indices I, J and K are given as an input to a function, so I cannot specify them like that.
A[:,:,1] yields a 2-dimensional DenseAxisArray. You should do collect on it to be able to aggregate via sum(..., dims=...). Hence you need to do:
julia> sum(collect(A[:,:,1]),dims = 2)
5×1 Matrix{AffExpr}:
A[1,1,1] + A[1,2,1] + A[1,3,1] + A[1,4,1] + A[1,5,1]
A[2,1,1] + A[2,2,1] + A[2,3,1] + A[2,4,1] + A[2,5,1]
A[3,1,1] + A[3,2,1] + A[3,3,1] + A[3,4,1] + A[3,5,1]
A[4,1,1] + A[4,2,1] + A[4,3,1] + A[4,4,1] + A[4,5,1]
A[5,1,1] + A[5,2,1] + A[5,3,1] + A[5,4,1] + A[5,5,1]
Please also note that your variable definition can be shortened to #variable(m, A[I, J, K] >= 0)
Finally, see my other recommendation on your model layout at your second question:
Summing columns of an array in model constraint in Julia

MATLAB array indexing and slicing

Im writing currently rewriting a Matlab script in C. When i get to the last few lines of the Matlab script a for loop is executed and it iterates through an array. Since i am trying to rewrite the program in C the slicing notation in the Matlab script is confusing me. I have attached the line of code that is troubling me below.
How would i write this line of code in a nested for loop indexing with i and j only, since you cant slice in c obviously. just for reference u = 1, Ubc is 2D array of size (NX+2, NY+2). Where NX = NY = 40.
Below is the line of code in Matlab i need to translate to for loop indexing.
Nx = 40;
Ny = 40;
u = 1;
Ubc = rand(Nx + 2, Ny + 2);
% First the i interfaces
F = 0.5* u *( Ubc(2:Nx+2,2:Ny+1) + Ubc(1:Nx+1,2:Ny+1))
- 0.5*abs(u)*( Ubc(2:Nx+2,2:Ny+1) - Ubc(1:Nx+1,2:Ny+1));
You can calculate the same in a loop as
Nx = 40;
Ny = 40;
u = 1;
Ubc = rand(Nx + 2, Ny + 2);
F = zeros(Nx + 1, Ny);
for z1 = 1 : Nx + 1
for z2 = 1 : Ny
F(z1, z2) = 0.5* u *( Ubc(z1 + 1, z2 + 1) + Ubc(z1, z2 + 1))
- 0.5*abs(u)*( Ubc(z1 + 1, z2 + 1) - Ubc(z1, z2 + 1));
end
end
You shouldn't use i and j as loop index in Matlab. Both are the imaginary unit.

Obtaining approximate derivatives with variable x spacing in MATLAB? [duplicate]

This question already has answers here:
Numerical derivative of a vector
(3 answers)
Closed 7 years ago.
I have two arrays: x and y. In practice, y is dependent on x, but both arrays are measured values. I would like to obtain the derivative of y with respect to x. If x were uniformly spaced (i.e. x=[1 2 3 4 5]), I could do something with diff like this:
h = 0.001;
x = -pi:h:pi;
f = sin(X);
y = diff(f)/h;
However, x is not uniformly spaced (i.e. x=[1 1.9 2.8 4.1]). How can I obtain the partial derivative of this data set?
A good way to do it is gradient,
dydx = gradient(y, x);
I like it because it returns a vector which is the same length as x and y. The downside though, is it's first order accurate. This can sometimes be a problem, a fix could be to write your own,
x = unique([linspace(0, 2*pi, 50), logspace(0, log10(2*pi), 50)]);
y = cos(x) ;
subplot(2,1,1) ;
plot(x, Gradient(y, x), x, gradient(y,x), x, -sin(x));
legend('2^{nd} order', '1^{st} order', 'exact') ;
subplot(2,1,2) ;
plot(x, Gradient(y, x) + sin(x), x, gradient(y,x) + sin(x));
legend('2^{nd} order - exact', '1^{st} order - exact')
With Gradient being
function dydx = Gradient(y,x)
y = y(:);
p = x(3:end) - x(2:end-1);
p = p(:);
m = x(2:end-1) - x(1:end-2);
m = m(:);
p1 = x(2) - x(1);
p2 = x(3) - x(1);
m1 = x(end) - x(end-1);
m2 = x(end) - x(end-2);
dydx = reshape([ ((-p1^2 + p2^2)*y(1) - p2^2*y(2) + p1^2*y(3))/(p1*(p1 - p2)*p2);
((-m.^2 + p.^2).*y(2:end-1) - p.^2.*y(1:end-2) + m.^2.*y(3:end))./(m.*p.*(m + p));
((m1^2 - m2^2)*y(end) + m2^2*y(end-1) - m1^2*y(end-2))/(m1^2*m2 - m1*m2^2) ...
], size(x));
end
Edit:
Improved it for multidimensional array and constant spacing support
function dydx = Gradient(y,x)
if length(y) < 3
dydx = gradient(y,x);
return
end
[~, n] = max(size(y));
N = ndims(y);
i = repmat({':'},1,N-1);
y = permute(y, [n, 1:n-1, n+1:N]);
if isscalar(x)
%"x" is actually a spacing value
p = x;
m = x;
p1 = x;
p2 = x;
m1 = x;
m2 = x;
else
if isvector(x)
x = repmat(x(:), size(y(1, i{:})));
else
x = permute(x, [n, 1:n-1, n+1:N]);
end
if all(size(x) ~= size(y))
error('Sizes of arrays must be the same.')
end
p = x(3:end, i{:}) - x(2:end-1, i{:});
m = x(2:end-1, i{:}) - x(1:end-2, i{:});
p1 = x(2, i{:}) - x(1, i{:});
p2 = x(3, i{:}) - x(1, i{:});
m1 = x(end, i{:}) - x(end-1, i{:});
m2 = x(end, i{:}) - x(end-2, i{:});
end
dydx = ipermute([ ((-p1.^2 + p2.^2).*y(1,i{:}) - p2.^2.*y(2,i{:}) + p1.^2.*y(3,i{:}))./(p1.*(p1 - p2).*p2);
((-m.^2 + p.^2).*y(2:end-1,i{:}) - p.^2.*y(1:end-2,i{:}) + m.^2.*y(3:end,i{:}))./(m.*p.*(m + p));
((m1.^2 - m2.^2).*y(end,i{:}) + m2.^2.*y(end-1,i{:}) - m1.^2.*y(end-2,i{:}))./(m1.^2.*m2 - m1.*m2.^2) ...
], [n, 1:n-1, n+1:N]);
end

Passing Arrays as a parameter to a VBA function

I have a user defined Excell worksheet function (Linear) that interpolates from an array of X and an array of Y values at a defined X1 value, which works fine. I have tried to use this within another function (NPL in the example code below) be setting it a a Private Static function within a VBA module and then calling the function using arrays of data created within the function.
When I use this in the spreadsheet I get a #VALUE error.
Any ideas what I am doing wrong?
Example code:
Function NPL(Length, Beam)
A = Array(1, 2, 3, 4)
B = Array(2, 4, 6, 8)
C = Linear(A, B, 1.5)
NPL = C
End Function
Private Static Function Linear(X, Y, X1)
N = 0
I = 1
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = X.Count
A = 0
I = 0
Do
I = I + 1
Loop Until X(I) > X1 Or I > N - 1
If X1 < X(N) And X1 > X(1) Then
Linear = Y(I - 1) + (X1 - X(I - 1)) * (Y(I) - Y(I - 1)) / (X(I) - X(I - 1))
ElseIf X1 > X(N) Or X1 = X(N) Then
Linear = Y(N)
Else
Linear = Y(1)
End If
End Function
Replace your
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = X.Count
with
Do
N = I
I = I + 1
Loop Until X(I) < X(I - 1) Or N = UBound(X) - LBound(X) + 1
This should work for any 1D array.

Numpy: values in array wont change

The below code is supposed to calculate some values and place them in incremental places in the numpy.zeros() array. The calculations all perform correctly but the array stays as just zeros. I could be missing something obvious so apologies if I am.
n = 256
lam = l
a = numpy.zeros([(len(z[0]) * len(z[:,0]) + n + 1), (n + len(z[0]))])
b = numpy.zeros([numpy.size(a, 0), 1])
#data fitting equations
k = 0
for i in range(len(z[0])):
for j in range(len(z[:,0])-1):
wij = smoother(z[j][i] + lam)
a[k][(z[j][i]+lam)] = float(wij)
print a[k][(z[j][i]+lam)]
a[k][n+j] = float(-wij)
b[k][0] = float(-wij * B[j])
k = k + 1
Thanks,
Tom
Answer supplied by Jaime works fine. Use
a[1, 2]
rather than
a[1][2]

Resources