'matrix' object has no attribute 'eigenvals' - python-3.x
I have the following code
import numpy as np
import sympy as sp
def bra(i,d):
arr = np.zeros((1,d))
if i <= (d-1):
arr[:,i] = 1
else:
print("Index Out of bounds")
return arr
def density(i,j,d):
return bra(i,d).T*bra(j,d)
SIGMA = (1/3)*(np.kron(np.kron(bra(0,3),bra(1,3)).T,np.kron(bra(0,3),bra(1,3)))+np.kron(np.kron(bra(1,3),bra(2,3)).T,np.kron(bra(1,3),bra(2,3)))+np.kron(np.kron(bra(2,3),bra(0,3)).T,np.kron(bra(2,3),bra(0,3))))
DELTA = (1/3)*(np.kron(np.kron(bra(1,3),bra(0,3)).T,np.kron(bra(1,3),bra(0,3)))+np.kron(np.kron(bra(2,3),bra(1,3)).T,np.kron(bra(2,3),bra(1,3)))+np.kron(np.kron(bra(0,3),bra(2,3)).T,np.kron(bra(0,3),bra(2,3))))
Essentially bra(i,d) gives a (1,d) array with (1,i)th element as one and rest as zero. For example,
bra(0,3)=[[1,0,0]]
bra(1,3)=[[0,1,0]]
bra(0,3)=[[0,0,1]]
density(i,j,d) returns (d,d) matrix with (i,j)th element as one rest as zero, for example,
density(0,1,3) = array([[0., 1., 0.], [0., 0., 0.],[0., 0., 0.]]).
Using the above codes, I have produced a (9,9) Matrix object by using np.kron
a = sp.symbols('a', positive = True)
HORO = (2/21)*(np.kron(density(0,0,3),density(0,0,3))+np.kron(density(1,0,3),density(0,1,3))+np.kron(density(0,0,3),density(2,2,3))
+np.kron(density(0,1,3),density(1,0,3))+np.kron(density(1,1,3),density(1,1,3))+np.kron(density(2,1,3),density(1,2,3))
+np.kron(density(0,2,3),density(2,0,3))+np.kron(density(1,2,3),density(2,1,3))+np.kron(density(2,2,3),density(2,2,3)))+(a/7)*SIGMA+((5-a)/7)*DELTA
M = np.asmatrix(HORO)
It can be shown that M matrix is invertible and it
is the following (9,9) matrix
matrix([[0.0952380952380952, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0.0476190476190476*a, 0, 0.0952380952380952, 0, 0, 0, 0, 0],
[0, 0, 0.333333333333333 - 0.0476190476190476*a, 0, 0, 0,
0.0952380952380952, 0, 0],
[0, 0.0952380952380952, 0,
0.238095238095238 - 0.0476190476190476*a, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0.0952380952380952, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0.0476190476190476*a, 0, 0.0952380952380952, 0],
[0, 0, 0, 0, 0, 0, 0.0476190476190476*a, 0, 0],
[0, 0, 0, 0, 0, 0.0952380952380952, 0,
0.238095238095238 - 0.0476190476190476*a, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0.0952380952380952]], dtype=object)
For this symbolic matrix I want to calculate the eigenvalues as
M.eigenvals()
However, it is returning the following error
AttributeError: 'matrix' object has no attribute 'eigenvals'
I can't figure out what went wrong.
Usually, numpy and sympy don't mix well. Numpy can't work with sympy functions and symbols. Also, sympy tries to calculate exact symbolic solutions, which doesn't work well together with floats (sympy strongly prefers integers, rationals and symbolic expressions such as sp.sqrt()).
In this case, provided you don't change too much, numpy managed to calculate the matrix elements well (sums and productions are executed via the underlying standard Python).
Now, if you just use that matrix in sympy, you get:
M = sp.Matrix(HORO)
print(M.eigenvals())
You get:
{0.0952380952380952: 3,
0.119047619047619 - 0.152455338986496 * sqrt(0.0975609756097561 * a ** 2 - 0.48780487804878 * a + 1.0): 2,
0.152455338986496 * sqrt(0.0975609756097561 * a ** 2 - 0.48780487804878 * a + 1.0) + 0.119047619047619: 2,
0.0476190476190476 * a: 1,
0.333333333333333 - 0.0476190476190476 * a: 1}
A better approach uses nsimplify to convert floats to rationals:
M = sp.Matrix(sp.nsimplify(HORO))
print(M.eigenvals())
This gives a nicer symbolic solution:
{2 / 21: 3,
5 / 42 - sqrt(4 * a ** 2 - 20 * a + 41) / 42: 2,
sqrt(4 * a ** 2 - 20 * a + 41) / 42 + 5 / 42: 2,
a / 21: 1,
1 / 3 - a / 21: 1}
Related
How to make a checkerboard in Pytorch?
I see that a simple checkerboard pattern can be created fairly concisely with numpy Does anyone know if a checkerboard where each square may contain multiple values could be created? E.g.: 1 1 0 0 1 1 1 1 0 0 1 1 0 0 1 1 0 0 0 0 1 1 0 0
Although there is no equivalent of np.indices in PyTorch, you can still find a workaround using a combination of torch.arange, torch.meshgrid, and torch.stack: def indices(h,w): return torch.stack(torch.meshgrid(torch.arange(h), torch.arange(w))) This allows you to define a base tensor with a checkboard pattern following your linked post: >>> base = indices(2,3).sum(axis=0) % 2 tensor([[0, 1, 0], [1, 0, 1]]) Then you can repeat the row end columns with torch.repeat_interleave: >>> base.repeat_interleave(2, dim=0).repeat_interleave(2, dim=1) tensor([[0, 0, 1, 1, 0, 0], [0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 1, 1]]) And you can take the opposite of a given checkboard x by computing 1-x. So you could define a function like this: def checkerboard(shape, k): """ shape: dimensions of output tensor k: edge size of square """ h, w = shape base = indices(h//k, w//k).sum(dim=0) % 2 x = base.repeat_interleave(k, 0).repeat_interleave(k, 1) return 1-x And try with: >>> checkerboard((4,6), 2) tensor([[1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 1, 1], [0, 0, 1, 1, 0, 0], [0, 0, 1, 1, 0, 0]])
How to initialize an 3D array variable in Gekko?
I'm trying to solve a step from a three-dimensional master timetabling model, which involvs periods(5), courses(19) and locations(8). So I have a problem to initialize these variables with an 3D array in Gekko. Without this initialization the algorithm doesn't converge, after more than 15 minutes run and 1000 iterations. When I try initialize, this error appears: " raise Exception(response) Exception: #error: Equation Definition Equation without an equality (=) or inequality (>,<) true STOPPING... " How can I fix this problem? Follows a version of my code: import numpy as np from gekko import GEKKO # Input data # Schedule of periods and courses sched = np.array([ [0, 1, 0, 0, 1], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], \ [0, 0, 0, 0, 1], [1, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0], \ [1, 0, 0, 1, 0], [0, 1, 0, 0, 1], [1, 1, 0, 0, 0], [0, 1, 1, 0, 0], \ [0, 1, 1, 0, 0], [1, 0, 0, 1, 0], [1, 0, 0, 1, 0], [0, 0, 1, 0, 1], \ [1, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 1, 0], [0, 1, 0, 0, 1] ], dtype=np.int64) # Initial allocation of all periods, courses and locations alloc=np.array([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,\ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], dtype=np.int64) # Number of students enrolled in each course enrol = np.array([ 60, 60, 60, 40, 40, 110, 120, 50, 60, 55, 50, \ 55, 40, 64, 72, 50, 50, 55, 55], dtype=np.float64) # Capacity of each location (classroom) capac = np.array([ 60, 60, 120, 60, 80, 60, 60, 65], dtype=np.float64) # Total costs of using each location costs = np.array([ 9017.12, 9017.12, 12050.24, 9017.12, 9413.68, 9017.12, \ 9017.12, 9188.96 ]) # Estimated cost of each location by period and student ecost = np.repeat(np.array([[costs[i]*pow(enrol[j]*5,-1) for j in range(19)] for i in range(8)]), 5) # The model construction m = GEKKO() # Constant arrays x = m.Array(m.Const,(19,5)) y = m.Array(m.Const,(8,19,5)) N = m.Array(m.Const,(19)) C = m.Array(m.Const,(8)) Ec = m.Array(m.Const,(8,19,5)) Ecy = m.Array(m.Const,(8,19,5)) Alt = m.Array(m.Const,(8,19,5)) for k in range(5): for j in range(19): N[j] = enrol[j] x[j,k] = sched[j,k] for i in range(8): C[i] = capac[i] Ec[i,j,k] = ecost[k+j*5+i*19*5] y[i,j,k] = alloc[k+j*5+i*19*5] Ecy[i,j,k] = Ec[i,j,k]*y[i,j,k] if sched[j,k]==1: Alt[i,j,np.where(sched[j,:]==1)[0][0]]=-sched[j,k]*(1-sum(sched[j,:])) if sum(sched[j,:])==2: Alt[i,j,np.where(sched[j,:]==1)[0][1]]=sched[j,k]*(1-sum(sched[j,:])) else: Alt[i,j,k]=0 # Initialize the variable z with the initial value y: # These commented approaches produce the error. z = m.Array(m.Var,(8,19,5),lb=0,ub=1,integer=True) #for i in range(8): # for j in range(19): # for k in range(5): # z[i,j,k] = y[i,j,k] # nor #z = m.Array(m.Var,(8,19,5),value=y,lb=0,ub=1,integer=True) # Intermediate equations Ecz = m.Array(m.Var,(8,19,5),lb=0) Altz = m.Array(m.Var,(8,19)) for i in range(8): for j in range(19): Altz[i,j]=m.Intermediate(m.sum(Alt[i,j,:]*z[i,j,:])) for k in range(5): Ecz[i,j,k]=m.Intermediate(Ec[i,j,k]*z[i,j,k]) # Constraints m.Equation(m.sum(m.sum(m.sum(Ecz)))<=m.sum(m.sum(m.sum(Ecy)))) for j in range(19): for k in range(5): m.Equation(m.sum(z[:,j,k])==x[j,k]) for i in range(8): for k in range(5): m.Equation(m.sum(z[i,:,k])==m.sum(y[i,:,k])) for i in range(8): for j in range(19): m.Equation(m.sum((C[i]/N[j]-x[j,:])*z[i,j,:])>=0) # Objective: to minimize the quantity of courses allocated in different locations # Example: with the solution y, I have 12 courses in different locations in the periods # print(sum([sum(Alt[i,j,:]*y[i,j,:])**2 for j in range(19) for i in range(8)])/2) for i in range(8): for j in range(19): m.Obj(Altz[i,j]**2/2) # Options and final results m.options.SOLVER=1 m.options.IMODE=2 m.solve() print(z) print(m.options.OBJFCNVAL) Note: My original problem has 20 periods, 171 courses, and 18 locations.
Use z[i,j,k].value = y[i,j,k] to give an initial guess for z. Using z[i,j,k] = y[i,j,k] redefines z entries as floating point numbers instead of gekko variable types. One other issue is that the variables Ecz and Altz are defined as Variables as m.Var and then overridden as Intermediates. Instead, try allocating them and assigning them as intermediates: Ecz = np.empty((8,19,5),dtype=object) Altz = np.empty((8,19),dtype=object) Use flatten() to simplify the summation of all elements of the 3 dimensional array. m.Equation(m.sum(Ecz.flatten())<=sum(Ecy.flatten())) The constant arrays can be defined as numpy arrays to avoid additional symbolic processing by Gekko. This speeds up the model compile time but has no effect on the final solution. x = np.empty((19,5)) y = np.empty((8,19,5)) N = np.empty((19)) C = np.empty((8)) Ec = np.empty((8,19,5)) Ecy = np.empty((8,19,5)) Alt = np.empty((8,19,5)) The IMODE should be 3 for optimization. IMODE=2 is for parameter regression. IMODE=2 should also work for this problem but 3 is the correct option because you aren't trying to fit to data. m.options.IMODE=3 Try using IPOPT to obtain an initial non-integer solution and then use APOPT to find an integer solution. m.solver_options = ['minlp_gap_tol 1.0e-2',\ 'minlp_maximum_iterations 10000',\ 'minlp_max_iter_with_int_sol 500',\ 'minlp_branch_method 1'] Mixed Integer Nonlinear Programming (MINLP) problems can be challenging to solve so you may need to use some of the solver options to speed up the solution. Try minlp_branch_method 1 to help the solver find an initial integer solution to do better pruning. The gap tolerance can also help to speed up the solution if a sub-optimal solution is okay. Below is the complete script. Consider using remote=False to run locally instead of using the public servers, especially for large optimization problems. import numpy as np from gekko import GEKKO # Input data # Schedule of periods and courses sched = np.array([ [0, 1, 0, 0, 1], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], \ [0, 0, 0, 0, 1], [1, 0, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0], \ [1, 0, 0, 1, 0], [0, 1, 0, 0, 1], [1, 1, 0, 0, 0], [0, 1, 1, 0, 0], \ [0, 1, 1, 0, 0], [1, 0, 0, 1, 0], [1, 0, 0, 1, 0], [0, 0, 1, 0, 1], \ [1, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 1, 0], [0, 1, 0, 0, 1] ], dtype=np.int64) # Initial allocation of all periods, courses and locations alloc=np.array([0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,\ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], dtype=np.int64) # Number of students enrolled in each course enrol = np.array([ 60, 60, 60, 40, 40, 110, 120, 50, 60, 55, 50, \ 55, 40, 64, 72, 50, 50, 55, 55], dtype=np.float64) # Capacity of each location (classroom) capac = np.array([ 60, 60, 120, 60, 80, 60, 60, 65], dtype=np.float64) # Total costs of using each location costs = np.array([ 9017.12, 9017.12, 12050.24, 9017.12, 9413.68, 9017.12, \ 9017.12, 9188.96 ]) # Estimated cost of each location by period and student ecost = np.repeat(np.array([[costs[i]*pow(enrol[j]*5,-1) for j in range(19)] for i in range(8)]), 5) # The model construction m = GEKKO(remote=True) # Constant arrays x = np.empty((19,5)) y = np.empty((8,19,5)) N = np.empty((19)) C = np.empty((8)) Ec = np.empty((8,19,5)) Ecy = np.empty((8,19,5)) Alt = np.empty((8,19,5)) for k in range(5): for j in range(19): N[j] = enrol[j] x[j,k] = sched[j,k] for i in range(8): C[i] = capac[i] Ec[i,j,k] = ecost[k+j*5+i*19*5] y[i,j,k] = alloc[k+j*5+i*19*5] Ecy[i,j,k] = Ec[i,j,k]*y[i,j,k] if sched[j,k]==1: Alt[i,j,np.where(sched[j,:]==1)[0][0]]=-sched[j,k]*(1-sum(sched[j,:])) if sum(sched[j,:])==2: Alt[i,j,np.where(sched[j,:]==1)[0][1]]=sched[j,k]*(1-sum(sched[j,:])) else: Alt[i,j,k]=0 # Initialize the variable z with the initial value y: # These commented approaches produce the error. z = m.Array(m.Var,(8,19,5),lb=0,ub=1,integer=True) for i in range(8): for j in range(19): for k in range(5): z[i,j,k].value = y[i,j,k] # nor #z = m.Array(m.Var,(8,19,5),value=y,lb=0,ub=1,integer=True) # Intermediate equations Ecz = np.empty((8,19,5),dtype=object) Altz = np.empty((8,19),dtype=object) for i in range(8): for j in range(19): Altz[i,j]=m.Intermediate(m.sum(Alt[i,j,:]*z[i,j,:])) for k in range(5): Ecz[i,j,k]=m.Intermediate(Ec[i,j,k]*z[i,j,k]) # Constraints m.Equation(m.sum(Ecz.flatten())<=sum(Ecy.flatten())) for j in range(19): for k in range(5): m.Equation(m.sum(z[:,j,k])==x[j,k]) for i in range(8): for k in range(5): m.Equation(m.sum(z[i,:,k])==m.sum(y[i,:,k])) for i in range(8): for j in range(19): m.Equation(m.sum((C[i]/N[j]-x[j,:])*z[i,j,:])>=0) # Objective: to minimize the quantity of courses allocated in different locations # Example: with the solution y, I have 12 courses in different locations in the periods # print(sum([sum(Alt[i,j,:]*y[i,j,:])**2 for j in range(19) for i in range(8)])/2) for i in range(8): for j in range(19): m.Obj(Altz[i,j]**2/2) # Options and final results m.options.IMODE=3 # Initialize with IPOPT m.options.SOLVER=3 m.solve() # Integer solution with APOPT m.options.SOLVER=1 m.solver_options = ['minlp_gap_tol 1.0e-2',\ 'minlp_maximum_iterations 10000',\ 'minlp_max_iter_with_int_sol 500',\ 'minlp_branch_method 1'] m.solve() print(z) print(m.options.OBJFCNVAL)
Hermitian Adjacency Matrix of Digraph
I am trying to find a pythonic way to calculate the Hermitian adjacency matrix in Python and I'm really struggling. The definition of a Hermitian Adjacency matrix is shown in this image: It works as follows. Lets say we have two nodes named i and j. If there is an directed edge going from both i to j and j to i, then the corresponding matrix value at location [ i, j ] should be set to 1. If there is only a directed edge from i to j, then the matrix element at location [i, j] should be set to +i. And if there is only a directed edge from j to i then the matrix element at location [i, j] should be set to -i. All other matrix values are set to 0. I cannot figure out a smart way to make this Hermitian Adjacency Matrix that doesn't involve iterating through my nodes one by one. Any advice?
I don't think there's a built-in for this, so I've cobbled together my own vectorised solution: import numpy as np import networkx as nx # Create standard adjacency matrix A = nx.linalg.graphmatrix.adjacency_matrix(G).toarray() # Add to its transpose and convert from sparse array B = A + A.T # Get row index matrix I = np.indices(B.shape)[0] + 1 # Apply vectorised formula to get Hermitian adjacency matrix H = np.multiply(B/2 * (2*I)**(B%2), 2*A-1).astype(int) Explanation Let's start with a directed graph: We start by creating the normal adjacency matrix using nx.linalg.graphmatrix.adjacency_matrix(), giving us the following matrix: >>> A = nx.linalg.graphmatrix.adjacency_matrix(G).toarray() [[1, 1, 0, 1, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 1, 0], [1, 1, 1, 1, 0, 1, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [1, 0, 0, 1, 0, 0, 0, 0], [1, 1, 0, 0, 1, 0, 1, 1], [0, 1, 0, 0, 1, 0, 0, 1], [0, 0, 0, 0, 1, 0, 0, 0]] We can then add this matrix to its transpose, giving us 2 in every location where there is a directed edge going from i to j and vice-versa, a 1 in every location where only one of these edges exists, and a 0 in every location where no edge exists: >>> B = A + A.T >>> B [[2, 2, 1, 1, 1, 2, 0, 0], [2, 0, 1, 2, 0, 1, 2, 0], [1, 1, 2, 1, 0, 1, 0, 0], [1, 2, 1, 0, 1, 0, 0, 0], [1, 0, 0, 1, 0, 1, 1, 1], [2, 1, 1, 0, 1, 0, 1, 1], [0, 2, 0, 0, 1, 1, 0, 1], [0, 0, 0, 0, 1, 1, 1, 0]] Now, we want to apply a function to the matrix so that 0 maps to 0, 2 maps to 1, and 1 maps to the row number i. We can use np.indices() to get the row number, and the following equation: x/2 * (2*i)**(x%2), where i is the row number and x is the element. Finally, we need to multiply elements in positions where no edge ij exists by -1. This can be vectorised as follows: >>> I = np.indices(B.shape)[0] + 1 >>> H = np.multiply(B/2 * (2*I)**(B%2), 2*A-1).astype(int) >>> H [[ 1, 1, -1, 1, -1, 1, 0, 0], [ 1, 0, -2, 1, 0, -2, 1, 0], [ 3, 3, 1, 3, 0, 3, 0, 0], [-4, 1, -4, 0, -4, 0, 0, 0], [ 5, 0, 0, 5, 0, -5, -5, -5], [ 1, 6, -6, 0, 6, 0, 6, 6], [ 0, 1, 0, 0, 7, -7, 0, 7], [ 0, 0, 0, 0, 8, -8, -8, 0]] As required. We can check that this is correct by using a naïve iterate-through-nodes approach: >>> check = np.zeros([8,8]) >>> for i in G.nodes: for j in G.nodes: if (i, j) in G.edges: if (j, i) in G.edges: check[i-1, j-1] = 1 else: check[i-1, j-1] = i else: if (j, i) in G.edges: check[i-1, j-1] = -i else: check[i-1, j-1] = 0 >>> (check == H).all() True
How to change only the diagonal elements of a 2D list?
So I am trying to create an NxN 2D array and then change its diagonal elemets to 1. Here is my code: arr=[1,1,1,2,2,2] table=[[0]*len(arr)]*len(arr) for i in range(0,len(arr)): table[i][i]=1 print(table) However, whenever I run this code, I get this output: [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1]] I am looking to get this: [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]] I have been staring at my code for hours and I cannot figure out what's wrong
The interesting thing about this is that you are really only editing one list in the for loop, but there are just five pointers to that list. (In this case, the list would be [0, 0, 0, 0, 0, 0].) You can see this by printing the id of each list in table by using id(): >>> for t in table: print(id(t)) 2236544254464 2236544254464 2236544254464 2236544254464 2236544254464 2236544254464 Your numbers are likely different than mine, but they are all the same number, nevertheless. You also can see that the edits to one list are applied to the others in table by putting a print(table) statement after each index assignment statement. So in order to 'fix' this, I would recommend using list comprehension instead. For example: table = [[0]*len(arr) for _ in range(len(arr))] If you checkout the ids of each list: >>> for t in table: print(id(t)) 2236544617664 2236544616064 2236544616320 2236544615872 2236544618368 2236544622720 Since they are different, you can now use the method for changing only the diagonals: >>> for i in range(0,len(arr)): table[i][i]=1 >>> table [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]
Your 2D "array" contains 6 lists which are the same list. Changes to any of those lists will also be reflected in the other lists. Consider this: >>> l = [0] * 6 >>> x = [l] >>> l[0] = 1 >>> l [1, 0, 0, 0, 0, 0] >>> x [[1, 0, 0, 0, 0, 0]] >>> x = [l, l, l] >>> x [[1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0]] >>> x[-1][-1] = 100 >>> x [[1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100]] This is because the list x contains the list l, so any changes to l are also seen through the reference to the same list in x. The problem is when multiplying mutable objects because it creates multiple references to the same mutable object. You should initialise your table like this: table = [[0 for j in range(len(arr))] for i in range(len(arr))] or table = [[0] * len(arr) for i in range(len(arr))] which, despite the use of multiplication, works because each list is different.
You can create your table and populate it simultaneously in nested loops: arr=[1,1,1,2,2,2] table = [] for i in range(len(arr)): table.append([0]*len(arr)) for j in range(len(arr)): if i == j: table[i][j] = 1 print(table) #[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]
Interesting. Try to use numpy to avoid list trap: import numpy as np org_row = [0]*5 l = [org_row]*5 x = np.array(l, np.int32) for i in range(len(x)): x[i][i]=1 print(x) output>: output> [[1 0 0 0 0] [0 1 0 0 0] [0 0 1 0 0] [0 0 0 1 0] [0 0 0 0 1]]
Finding a sequence of numbers in a multi dimensional list
How do I find if a sequence of numbers exists in a two-dimensional list? i.e. matrix: [[1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]] if [1,1,1] in matrix: print("It's in there") else: print("It's not there") I guess I could turn every int into a string but is there a slicker way?
Using an iterator over each cell of the matrix, I've managed to get a basic idea of what you wanted to achieve in Python script. matrix = [[1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]] matchCount = 0 lastNumber = None for cell in matrix: for number in cell: if number == 1 and lastNumber == 1 or lastNumber == None: matchCount += 1 if matchCount >= 3: print("MATCH in cell " + str(cell)) lastNumber = number matchCount = 0 lastNumber = None What happens is, it steps into the cell. It it's the first iteration then allow entry into our iterator. We don't know if it's a match list yet, so push it back in our little list. Stepping over and over, if we get enough matches in a row, then wonderful! Print we found a match in our matrix's cell!