Let N be a (linear) single-layer perceptron with weight matrix w of dimension nxn.
I want to train N under the Boolean constraint that the condition number k(w) of the weights w remain below a given threshold k_0 at each step of the optimisation.
Is there a standard way to implement this constraint (in pytorch, say)?
After each optimizer step, go through the list of parameters and recondition all matrices:
(code looked at for a few seconds, but not tested)
def recondition_(x, max_cond): # would need to be fixed for non-square x
u, s, vh = torch.linalg.svd(x)
curr_cond = s[0] / s[-1]
if curr_cond > max_cond:
ratio = curr_cond / max_cond
mult = torch.linspace(0, math.log(ratio), len(s)).exp()
s = mult * s
x[:] = torch.mm(u, torch.mm(torch.diag(s), vh))
Training loop:
...
optimizer.step()
with torch.no_grad():
for p in model.parameters():
if p.dim() == 2:
recondition_(p, max_cond)
...
I saw the boolean expressions for the N Queens problem from here.
My modified N queens rules are simpler:
For a p*p chessboard I want to place N queens in such a way so that
Queens will be placed adjacently, rows will be filled first.
p*p chessboard size will be adjusted until it can hold N queens
For example, say N = 17, then we need a 5*5 chessboard and the placement will be:
Q_Q_Q_Q_Q
Q_Q_Q_Q_Q
Q_Q_Q_Q_Q
Q_Q_*_*_*
*_*_*_*_*
The question is I am trying to come up with a boolean expression for this problem.
This problem can be solved using the Python packages humanize and omega.
"""Solve variable size square fitting."""
import humanize
from omega.symbolic.fol import Context
def pick_chessboard(q):
ctx = Context()
# compute size of chessboard
#
# picking a domain for `p`
# requires partially solving the
# problem of computing `p`
ctx.declare(p=(0, q))
s = f'''
(p * p >= {q}) # chessboard fits the queens, and
/\ ((p - 1) * (p - 1) < {q}) # is the smallest such board
'''
u = ctx.add_expr(s)
d, = list(ctx.pick_iter(u)) # assert unique solution
p = d['p']
print(f'chessboard size: {p}')
# compute number of full rows
ctx.declare(x=(0, p))
s = f'x = {q} / {p}' # integer division
u = ctx.add_expr(s)
d, = list(ctx.pick_iter(u))
r = d['x']
print(f'{r} rows are full')
# compute number of queens on the last row
s = f'x = {q} % {p}' # modulo
u = ctx.add_expr(s)
d, = list(ctx.pick_iter(u))
n = d['x']
k = r + 1
kword = humanize.ordinal(k)
print(f'{n} queens on the {kword} row')
if __name__ == '__main__':
q = 10 # number of queens
pick_chessboard(q)
Representing multiplication (and integer division and modulo) with binary decision diagrams has complexity exponential in the number of variables, as proved in: https://doi.org/10.1109/12.73590
I have for example, 1000 customers located in Europe with different latitude and longitude. I want to find the minimal number of facilities that can serve all customers, subject to the constraint that each customer must be served within 24hr delivery (here I use a maximum allowed transportation distance from a facility to a customer as the constraint for ensuring 24hr delivery service (distance is straight line between two locations, calculated based on Euclidean distance/straight line).
So, with each warehouse that can only serve the customers within certain distance e.g. 600 km, what is the algorithms that can help me to find the minimal number of facilities needed to service all customers, and their respective latitude and longitude. An example is shown in the attached pic below.
example of finding minimal warehouses and their locaitons
This falls in the category of facility location problems. There is quite a rich literature about these problems. The p-center problem is close to what you want.
Some notes:
Besides solving a formal mathematical optimization model, often heuristics (and meta-heuristics) are used.
The distances are a rough approximation of real travel time. That also means approximate solutions are probably good enough.
Besides just finding the minimum number of facilities needed to service all customers, we can refine the locations by minimizing the distances.
A math programming model for the pure "minimize number of facilities" can be formulated as a Mixed Integer Quadratically Constrained problem (MIQCP). This can be solved with standard solvers (e.g. Cplex and Gurobi). Below is an example I cobbled together:
With 1000 random customer locations, I can find a proven optimal solution:
---- 57 VARIABLE n.L = 4.000 number of open facilties
---- 57 VARIABLE isopen.L use facility
facility1 1.000, facility2 1.000, facility3 1.000, facility4 1.000
---- 60 PARAMETER locations
x y
facility1 26.707 31.796
facility2 68.739 68.980
facility3 28.044 67.880
facility4 76.921 34.929
See here for more details.
Basically we solve two models:
Model 1 finds the number of warehouses needed (minimize number subject to maximum distance constraint)
Model 2 finds the optimal placement of the warehouses (minimize total distance)
After solving model 1 we see (for a 50 customer random problem):
We need three warehouses. Although no link exceeds the maximum distance constraint, this is not an optimal placement.
After solving model 2 we see:
This now optimally places the three warehouses by minimizing the sum of length of the links. To be precise I minimized the sum of the squared lengths. Getting rid of the square root allowed me to use a quadratic solver.
Both models are of the convex Mixed Integer Quadratically Constrained Problem type (MIQCP). I used a readily available solver to solve these models.
Python codes with Gurobi as the solver:
from gurobipy import *
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
customer_num=15
dc_num=10
minxy=0
maxxy=10
M=maxxy**2
max_dist=3
service_level=0.7
covered_customers=math.ceil(customer_num*service_level)
n=0
customer = np.random.uniform(minxy,maxxy,[customer_num,2])
#Model 1 : Minimize number of warehouses
m = Model()
###Variable
dc={}
x={}
y={}
assign={}
for j in range(dc_num):
dc[j] = m.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="DC%d" % j)
x[j]= m.addVar(lb=0, ub=maxxy, vtype=GRB.CONTINUOUS, name="x%d" % j)
y[j] = m.addVar(lb=0, ub=maxxy, vtype=GRB.CONTINUOUS, name="y%d" % j)
for i in range(len(customer)):
for j in range(len(dc)):
assign[(i,j)] = m.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="Cu%d from DC%d" % (i,j))
###Constraint
for i in range(len(customer)):
for j in range(len(dc)):
m.addConstr(((customer[i][0] - x[j])*(customer[i][0] - x[j]) +\
(customer[i][1] - y[j])*(customer[i][1] - \
y[j])) <= max_dist*max_dist + M*(1-assign[(i,j)]))
for i in range(len(customer)):
m.addConstr(quicksum(assign[(i,j)] for j in range(len(dc))) <= 1)
for i in range(len(customer)):
for j in range(len(dc)):
m.addConstr(assign[(i, j)] <= dc[j])
for j in range(dc_num-1):
m.addConstr(dc[j] >= dc[j+1])
m.addConstr(quicksum(assign[(i,j)] for i in range(len(customer)) for j in range(len(dc))) >= covered_customers)
#sum n
for j in dc:
n=n+dc[j]
m.setObjective(n,GRB.MINIMIZE)
m.optimize()
print('\nOptimal Solution is: %g' % m.objVal)
for v in m.getVars():
print('%s %g' % (v.varName, v.x))
# # print(v)
# #Model 2: Optimal location of warehouses
optimal_n=int(m.objVal)
m2 = Model() #create Model 2
# m_new = Model()
###Variable
dc={}
x={}
y={}
assign={}
d={}
for j in range(optimal_n):
x[j]= m2.addVar(lb=0, ub=maxxy, vtype=GRB.CONTINUOUS, name="x%d" % j)
y[j] = m2.addVar(lb=0, ub=maxxy, vtype=GRB.CONTINUOUS, name="y%d" % j)
for i in range(len(customer)):
for j in range(optimal_n):
assign[(i,j)] = m2.addVar(lb=0,ub=1,vtype=GRB.BINARY, name="Cu%d from DC%d" % (i,j))
for i in range(len(customer)):
for j in range(optimal_n):
d[(i,j)] = m2.addVar(lb=0,ub=max_dist*max_dist,vtype=GRB.CONTINUOUS, name="d%d,%d" % (i,j))
###Constraint
for i in range(len(customer)):
for j in range(optimal_n):
m2.addConstr(((customer[i][0] - x[j])*(customer[i][0] - x[j]) +\
(customer[i][1] - y[j])*(customer[i][1] - \
y[j])) - M*(1-assign[(i,j)]) <= d[(i,j)])
m2.addConstr(d[(i,j)] <= max_dist*max_dist)
for i in range(len(customer)):
m2.addConstr(quicksum(assign[(i,j)] for j in range(optimal_n)) <= 1)
m2.addConstr(quicksum(assign[(i,j)] for i in range(len(customer)) for j in range(optimal_n)) >= covered_customers)
L=0
L = quicksum(d[(i,j)] for i in range(len(customer)) for j in range(optimal_n))
m2.setObjective(L,GRB.MINIMIZE)
m2.optimize()
#########Print Optimization Result
print('\nOptimal Solution is: %g' % m2.objVal)
dc_x=[]
dc_y=[]
i_list=[]
j_list=[]
g_list=[]
d_list=[]
omit_i_list=[]
for v in m2.getVars():
print('%s %g' % (v.varName, v.x))
if v.varName.startswith("x"):
dc_x.append(v.x)
if v.varName.startswith("y"):
dc_y.append(v.x)
if v.varName.startswith("Cu") and v.x == 1:
print([int(s) for s in re.findall("\d+", v.varName)])
temp=[int(s) for s in re.findall("\d+", v.varName)]
i_list.append(temp[0])
j_list.append(temp[1])
g_list.append(temp[1]+len(customer)) #new id mapping to j_list
if v.varName.startswith("Cu") and v.x == 0:
temp=[int(s) for s in re.findall("\d+", v.varName)]
omit_i_list.append(temp[0])
if v.varName.startswith("d") and v.x > 0.00001:
d_list.append(v.x)
#########Draw Netword
# prepare data
dc_cor=list(zip(dc_x,dc_y))
dc_list=[]
for i,k in enumerate(dc_cor):
temp=len(customer)+i
dc_list.append(temp)
df=pd.DataFrame({'Customer':i_list,'DC':j_list,'DC_drawID':g_list,'Sqr_distance':d_list})
df['Sqrt_distance']=np.sqrt(df['Sqr_distance'])
print(df)
dc_customer=[]
for i in dc_list:
dc_customer.append(df[df['DC_drawID'] == i]['Customer'].tolist())
print('\n', dc_customer)
#draw
G = nx.DiGraph()
d_node=[]
e = []
node = []
o_node = []
for c, k in enumerate(dc_list):
G.add_node(k, pos=(dc_cor[c][0], dc_cor[c][1]))
d_node.append(c)
v = dc_customer[c]
for n, i in enumerate(v):
G.add_node(i, pos=(customer[i][0], customer[i][1]))
u = (k, v[n])
e.append(u)
node.append(i)
G.add_edge(k, v[n])
for m,x in enumerate(omit_i_list):
G.add_node(x, pos=(customer[x][0], customer[x][1]))
o_node.append(x)
nx.draw_networkx_nodes(G, dc_cor, nodelist=d_node, with_labels=True, width=2, style='dashed', font_color='w', font_size=10, font_family='sans-serif', node_shape='^',
node_size=400)
nx.draw_networkx_nodes(G, customer, nodelist=o_node, with_labels=True, width=2, style='dashed', font_color='w', font_size=10, font_family='sans-serif', node_color='purple',
node_size=400)
nx.draw(G, nx.get_node_attributes(G, 'pos'), nodelist=node, edgelist=e, with_labels=True,
width=2, style='dashed', font_color='w', font_size=10, font_family='sans-serif', node_color='purple')
# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter('Optimization_Result.xlsx', engine='xlsxwriter')
# Convert the dataframe to an XlsxWriter Excel object.
df.to_excel(writer, sheet_name='Sheet1')
writer.save()
plt.axis('on')
plt.show()
We can calculate min cost suppose take this recurrence relation
min(mat[i-1][j],mat[i][j-1])+mat[i][j];
0 1 2 3
4 5 6 7
8 9 10 11
for calculating min cost using the above recurrence relation we will get for min-cost(1,2)=0+1+2+6=9
i am getting min cost sum, that's not problem..now i want to print the elements 0,1,2,6 bcz this elements are making min cost path.
Any help is really appreciated.
Suppose, your endpoint is [x, y] and start-point is [a, b]. After the recursion step, now start from the endpoint and crawl-back/backtrack to start point.
Here is the pseudocode:
# Assuming grid is the given input 2D grid
output = []
p = x, q = y
while(p != a && q != b):
output.add(grid[p][q])
min = infinity
newP = -1, newQ = -1
if(p - 1 >= 0 && mat[p - 1][q] < min):
min = matrix[p -1][q]
newP = p - 1
newQ = q
if(q - 1 >= 0 && mat[p][q - 1] < min):
min = mat[p][q - 1]
newP = p
newQ = q - 1
p = newP, q = newQ
end
output.add(grid[a][b])
# print output
Notice, here we used mat and grid - two 2D matrix where grid is the given input and mat is the matrix generated after the recursion step mat[i][j] = min(mat[i - 1][j], mat[i][j - 1]) + grid[i][j]
Hope it helps!
Besides computing the min cost matrix using the relation that you mentioned, you can also create a predecessor matrix.
For each cell (i, j), you should also store the information about who was the "min" in the relation that you mentioned (was it the left element, or is it the element above?). In this way, you will know for each cell, which is its preceding cell in an optimal path.
Afterwards, you can generate the path by starting from the final cell and moving backwards according to the "predecessor" matrix, until you reach the top-left cell.
Note that the going backwards idea can be applied also without explicitly constructing a predecessor matrix. At each point, you would need to look which of the candidate predecessors has a lower total cost.
How to insert a vector with different length to a matrix? For example I have a randomly located nodes=10; After that I am finding who are the neighbours of this nodes for example for node: i = 2 neighbours are nodes: j = 5 and 6, so the vector which containts this value is neighb_i = [neighb_i j]; but maybe I have to add some zeros to fill the vector till the length of a matrix ( in this case nodes are 10, so the matrix will be 10x10 ) But I want to keep all the values of neighbours for all nodes in a matrix, because when I am using a vector after the next interation this value is replacing themselves so at the next iteration when i = 3 I don't have information about when i = 2. How can I store this in a matrix, which has length nodes x nodes ?
close all
clear all
clc
x = 2000; %m
y = 2000; %m
nodes = 8;
%% Random location and direction, calculating the distance;
loc_x = x*rand(1,nodes)
loc_y = y*rand(1,nodes)
loc = [loc_x' loc_y']
dist(loc_x);
dist(loc_y);
distance = sqrt(dist(loc_x).^2 + dist(loc_y).^2) % = dist(loc')
distance(1:nodes+1:nodes^2) = inf; % replace zero diagonal with infinity
%% Power:
noise_power_dBm = -90; %dBm
noise_power_w = 10^((noise_power_dBm - 30)/10); % W
% The channel is based on a path-loss model in which is distance between nodes i and j
% and 3 - is attenuation exponent considerd as 3 ( 1:6 )
channel_gain = (1)./(distance).^3; %dB
channel_gain(1:nodes+1:nodes^2) = inf; % replace zero diagonal with infinity
min_SNR_dB = 10; %dB, minimum required SNR at the receiving nodes
min_SNR = 10^(min_SNR_dB/10);
p_max_dBm = 10; % dBm
p_max_w = 10^((p_max_dBm - 30)/10); % W
p_uni = (min_SNR*noise_power_w)./(channel_gain); % unicast power between two nodes
p_uni(1:nodes+1:nodes^2) = inf; % replace zero diagonal with infinity
plot(loc_x,loc_y,'r*');
change = 1;
cost = inf(1,nodes) % at the beginning cost of all nodes are infinity
cost(1) = 0; % except the cost of node 1 = 0 ( source node )
while change == 1 % change is when a child chooses parent node and change its parent node; if its a =1 its go again in for loops
change = 0; % when i am coming inside while loop I change the change parameter to 0 and if some changes occurse
for i = 2:nodes %i - child node first i = 2, then j is 1,2,3...8 it checks all the nodes starts from 1 because source node can be a neighbour of other node
neighb_i = [];
for j = 1:nodes % j - parent node
if p_uni(i,j) < p_max_w
neighb_i = [neighb_i j]; %Found who are the neighbours ; to use a matrix not a vector ????????
end
% calculate the cost for every nodes First Dijkstra, later MC
% and choose the parent node for every node ; if we have some changes
% ---> change = 1
for k = [neighb_i j] % neighb_i
% cost(i,k) = 1:nodes;
end
end
keyboard
end
% At the end of this while - I have to know what is the parent node for
% every node and when I come out I can draw a graph.
end
%%
gplot(nodes,loc)
%plot(source,'b*');
plot(loc_x,loc_y,'rO');
axis([x y x y]);
hold on;
grid on;
grid on, xlabel('x'), ylabel('y');
title('Random nodes');