def compressed_sensing2(x1, trans): """L1 compressed sensing :Parameters: x1 : array-like, shape=(n_outputs,) input sparse vector trans : array-like, shape=(n_outputs, n_inputs) transformation matrix :Returns: decoded vector, shape=(n_inpus,) :RType: array-like """ # obrain sizes of inputs and outputs (n_outputs, n_inputs) = trans.shape # define variable t = fd.oovar('t', size=n_inputs) x = fd.oovar('x', size=n_inputs) # objective to minimize: f x^T -> min objective = fd.sum(t) # init constraints constraints = [] # equality constraint: a_eq x^T = b_eq constraints.append(fd.dot(trans, x) == x1) # inequality constraint: -t < x < t constraints.append(-t <= x) constraints.append(x <= t) # start_point start_point = {x:np.zeros(n_inputs), t:np.zeros(n_inputs)} # solve linear programming prob = LP(objective, start_point, constraints=constraints) result = prob.minimize('pclp') # glpk, lpSolve... if available # print result # print "x =", result.xf # arguments at mimimum # print "objective =", result.ff # value of objective return result.xf[x]
def fit_kernel_model(kernel, loss, X, y, gamma, weights=None): n_samples = X.shape[0] gamma = float(gamma) if weights is not None: weights = weights / np.sum(weights) * weights.size # --- optimize bias term --- bias = fd.oovar('bias', size=1) if weights is None: obj_fun = fd.sum(loss(y, bias)) else: obj_fun = fd.sum(fd.dot(weights, loss(y, bias))) optimizer = NLP(obj_fun, {bias: 0.}, ftol=1e-6, iprint=-1) result = optimizer.solve('ralg') bias = result(bias) # --- optimize betas --- beta = fd.oovar('beta', size=n_samples) # gram matrix K = kernel(X, X) assert K.shape == (n_samples, n_samples) K_dot_beta = fd.dot(K, beta) penalization_term = gamma * fd.dot(beta, K_dot_beta) if weights is None: loss_term = fd.sum(loss(y - bias, K_dot_beta)) else: loss_term = fd.sum(fd.dot(weights, loss(y - bias, K_dot_beta))) obj_fun = penalization_term + loss_term beta0 = np.zeros((n_samples, )) optimizer = NLP(obj_fun, {beta: beta0}, ftol=1e-4, iprint=-1) result = optimizer.solve('ralg') beta = result(beta) return KernelModel(X, kernel, beta, bias)
def __init__(self, f, x, test = 'f'): self.f = f self.x = x.copy() # sA = FuncDesigner.oovar('A',shape=(len(x),len(x))) sx = FuncDesigner.oovar('x', size = len(x)) sy = 0.5*FuncDesigner.dot(sx*sx,FuncDesigner.dot(f.A,sx)) print 'sy=',sy # self.sA = sA self.sx = sx self.sy = sy
def __init__(self, f, x, test = 'f'): self.f = f self.x = x.copy() # sA = FuncDesigner.oovar('A',shape=(len(x),len(x))) sx = FuncDesigner.oovar('x', size = len(x)) sy = 0.5*FuncDesigner.dot(sx*sx,FuncDesigner.dot(f.A,sx)) print('sy=',sy) # self.sA = sA self.sx = sx self.sy = sy
def addVar(self, lb=0, ub=GRB.INFINITY, vtype="C", name="", init=0.0): if name == "": self.var_id += 1 name = "x_{0}".format(self.var_id) if vtype == "C" or vtype == GRB.CONTINUOUS: CAT = None elif vtype == "I" or vtype == GRB.INTEGER: CAT = int elif vtype == "B" or vtype == GRB.BINARY: CAT = bool var = fd.oovar(name=name, lb=lb, ub=ub, domain=CAT) self.variables.append(var) self.init[var] = init return var
def Pyomo2FD_expression(exp, ipoint, vars, symbol_map): if isinstance(exp, expr._IntrinsicFunctionExpression): if not exp.name in intrinsic_function_expressions: logger.error("Unsupported intrinsic function (%s)", exp.name) raise TypeError("FuncDesigner does not support '{0}' expressions".format(exp.name)) args = [] for child_exp in exp._args: args.append( Pyomo2FD_expression(child_exp, ipoint, vars, symbol_map)) fn = intrinsic_function_expressions[exp.name] return fn(*tuple(args)) elif isinstance(exp, expr._SumExpression): args = [] for child_exp in exp._args: args.append( Pyomo2FD_expression(child_exp, ipoint, vars, symbol_map) ) iargs = args.__iter__() # # NOTE: this call to FuncDesigner.sum() _must_ be passed a list. If a # generator is passed to this function, then an unbalanced expression tree will # be generated that is not well-suited for large models! # if six.PY2: return FuncDesigner.sum([c*iargs.next() for c in exp._coef]) + exp._const else: return FuncDesigner.sum([c*next(iargs) for c in exp._coef]) + exp._const elif isinstance(exp, expr._ProductExpression): ans = exp._coef for n in exp._numerator: ans *= Pyomo2FD_expression(n, ipoint, vars, symbol_map) for n in exp._denominator: ans /= Pyomo2FD_expression(n, ipoint, vars, symbol_map) return ans #elif isinstance(exp, expr._InequalityExpression): #args = [] #for child_exp in exp._args: #args.append( Pyomo2FD_expression(child_exp, ipoint, vars, symbol_map) ) # #ans = args[0] #for i in xrange(len(args)-1): ## FD doesn't care whether the inequality is strict #ans = ans < args[i+1] #return ans #elif isinstance(exp, expr._InequalityExpression): #return Pyomo2FD_expression(exp._args[0], ipoint, vars) == Pyomo2FD_expression(exp._args[1], ipoint, vars, symbol_map) elif isinstance(exp, _ExpressionData): return Pyomo2FD_expression(exp._args[0], ipoint, vars, symbol_map) elif (isinstance(exp,var._VarData) or isinstance(exp,var.Var)) and not exp.is_fixed(): vname = symbol_map.getSymbol(exp, labeler) if not vname in vars: vars[vname] = FuncDesigner.oovar(vname) ipoint[vars[vname]] = 0.0 if exp.value is None else exp.value #symbol_map.getSymbol(exp, lambda obj,x: x, vname) return vars[vname] elif isinstance(exp,param._ParamData): return exp.value elif type(exp) in intlist: return exp elif isinstance(exp,numvalue.NumericConstant) or exp.is_fixed(): return exp.value else: raise ValueError("Unsupported expression type in Pyomo2FD_expression: "+str(type(exp)))
def Pyomo2FD_expression(exp, ipoint, vars, symbol_map): if isinstance(exp, expr._IntrinsicFunctionExpression): if not exp.name in intrinsic_function_expressions: logger.error("Unsupported intrinsic function (%s)", exp.name) raise TypeError( "FuncDesigner does not support '{0}' expressions".format( exp.name)) args = [] for child_exp in exp._args: args.append( Pyomo2FD_expression(child_exp, ipoint, vars, symbol_map)) fn = intrinsic_function_expressions[exp.name] return fn(*tuple(args)) elif isinstance(exp, expr._SumExpression): args = [] for child_exp in exp._args: args.append( Pyomo2FD_expression(child_exp, ipoint, vars, symbol_map)) iargs = args.__iter__() # # NOTE: this call to FuncDesigner.sum() _must_ be passed a list. If a # generator is passed to this function, then an unbalanced expression tree will # be generated that is not well-suited for large models! # if six.PY2: return FuncDesigner.sum([c * iargs.next() for c in exp._coef]) + exp._const else: return FuncDesigner.sum([c * next(iargs) for c in exp._coef]) + exp._const elif isinstance(exp, expr._ProductExpression): ans = exp._coef for n in exp._numerator: ans *= Pyomo2FD_expression(n, ipoint, vars, symbol_map) for n in exp._denominator: ans /= Pyomo2FD_expression(n, ipoint, vars, symbol_map) return ans #elif isinstance(exp, expr._InequalityExpression): #args = [] #for child_exp in exp._args: #args.append( Pyomo2FD_expression(child_exp, ipoint, vars, symbol_map) ) # #ans = args[0] #for i in xrange(len(args)-1): ## FD doesn't care whether the inequality is strict #ans = ans < args[i+1] #return ans #elif isinstance(exp, expr._InequalityExpression): #return Pyomo2FD_expression(exp._args[0], ipoint, vars) == Pyomo2FD_expression(exp._args[1], ipoint, vars, symbol_map) elif isinstance(exp, _ExpressionData): return Pyomo2FD_expression(exp._args[0], ipoint, vars, symbol_map) elif (isinstance(exp, var._VarData) or isinstance(exp, var.Var)) and not exp.is_fixed(): vname = symbol_map.getSymbol(exp, labeler) if not vname in vars: vars[vname] = FuncDesigner.oovar(vname) ipoint[vars[vname]] = 0.0 if exp.value is None else exp.value #symbol_map.getSymbol(exp, lambda obj,x: x, vname) return vars[vname] elif isinstance(exp, param._ParamData): return exp.value elif type(exp) in intlist: return exp elif isinstance(exp, numvalue.NumericConstant) or exp.is_fixed(): return exp.value else: raise ValueError( "Unsupported expression type in Pyomo2FD_expression: " + str(type(exp)))
def solve(self, *args, **kw): if len(args) > 1: self.err(''' incorrect number of arguments for solve(), must be at least 1 (solver), other must be keyword arguments''') if self.start is None and not self.returnToStart: self.err('for returnToStart=False mode you should provide start, other cases are unimplemented yet') solver = args[0] if len(args) != 0 else kw.get('solver', self.solver) KW = self.__init_kwargs.copy() KW.update(kw) objective = KW.get('objective', self.objective) if isinstance(objective, (list, tuple, set)): nCriteria = len(self.objective) if 3 * nCriteria != np.asarray(self.objective).size: objective = [(objective[3*i], objective[3*i+1], objective[3*i+2]) for i in range(int(round(np.asarray(self.objective).size / 3)))] if len(objective) == 1: KW['fTol'], KW['goal'] = objective[0][1:] else: objective = [(self.objective, KW.get('fTol', getattr(self, 'fTol')), KW.get('goal', getattr(self, 'goal')))] nCriteria = len(objective) isMOP = nCriteria > 1 mainCr = objective[0][0] import FuncDesigner as fd, openopt as oo solverName = solver if type(solver) == str else solver.__name__ is_interalg = solverName == 'interalg' is_glp = solverName == 'sa' if is_glp: assert nCriteria == 1, 'you cannot solve multiobjective tsp by the solver' is_interalg_raw_mode = is_interalg and KW.get('dataHandling', oo.oosolver(solver).dataHandling) in ('auto','raw') KW.pop('objective', None) P = oo.MOP if nCriteria > 1 else oo.GLP if is_interalg else oo.MILP if not is_glp else oo.GLP import networkx as nx graph = self.graph # must be networkx Graph instance init_graph_is_directed = graph.is_directed() init_graph_is_multigraph = graph.is_multigraph() if not init_graph_is_multigraph or not init_graph_is_directed: graph = nx.MultiDiGraph(graph) #if init_graph_is_directed else nx.MultiGraph(graph) nodes = graph.nodes() edges = graph.edges() n = len(nodes) m = len(edges) node2index = dict([(node, i) for i, node in enumerate(nodes)]) # TODO: implement MOP with interalg_gdp mode (requires interpolation interval analysis for non-monotone funcs) interalg_gdp = 1 if not is_interalg:# or isMOP: # !!!!!!!!!!!!! TODO: add handling of MOP with interalg_gdp? interalg_gdp = 0 if interalg_gdp: x = [] edge_ind2x_ind_val = {} else: pass #x = fd.oovars(m, domain=bool) #cr_values = dict([(obj[0], []) for obj in objective]) cr_values = {} constraints = [] EdgesDescriptors, EdgesCoords = [], [] # mb rework it by successors etc? Funcs = {} Cons = KW.pop('constraints', []) if type(Cons) not in (list, tuple): Cons = [Cons] usedValues = getUsedValues(Cons) usedValues.update(getUsedValues([obj[0] for obj in objective])) MainCr = mainCr if type(mainCr) in (str, np.str_) else list(usedValues)[0] isMainCrMin = objective[0][2] in ('min', 'minimum') node_out_edges_num = [] for node in nodes: Edges = graph[node] node_out_edges_num.append(len(Edges)) out_nodes = Edges.keys() if len(out_nodes) == 0: self.err('input graph has node %s that does not lead to any other node; solution is impossible' % node) if init_graph_is_multigraph and not isMOP and type(mainCr) in [str, np.str_]: W = {} for out_node in out_nodes: ww = list(Edges[out_node].values()) for w in ww: tmp = W.get(out_node, None) if tmp is None: W[out_node] = w continue th = tmp[mainCr] w_main_cr_val = w[mainCr] if isMainCrMin == (th > w_main_cr_val): W[out_node] = w Out_nodes, W = np.array(list(W.keys())), np.array(list(W.values())) else: W = np.hstack([list(Edges[out_node].values()) for out_node in out_nodes]) Out_nodes = np.hstack([[out_node] * len(Edges[out_node]) for out_node in out_nodes]) if interalg_gdp: rr = np.array([w[MainCr] for w in W]) if isMainCrMin: rr = -rr elif objective[0][2] not in ('max', 'maximum'): self.err('unimplemented for fixed value goal in TSP yet, only min/max is possible for now') ind = rr.argsort() W = W[ind] Out_nodes = Out_nodes[ind] lc = 0 for i, w in enumerate(W): if interalg_gdp: edge_ind2x_ind_val[len(EdgesCoords)] = (len(x), lc) lc += 1 EdgesCoords.append((node, Out_nodes[i])) EdgesDescriptors.append(w) for key, val in w.items(): # for undirected: #if node2index[key] < node2index[out_node]: continue Val = val if self.returnToStart or node != self.start else 0 if key in cr_values: cr_values[key].append(Val) else: cr_values[key] = [Val] if interalg_gdp: x.append(fd.oovar(domain = np.arange(lc))) m = len(EdgesCoords) # new value if is_glp: if type(mainCr) not in (str, np.str_): self.err('for the solver "sa" only text name objectives are implemented (e.g. "time", "price")') if init_graph_is_multigraph: self.err('the solver "sa" cannot handle multigraphs yet') if len(Cons) != 0: self.err('the solver "sa" cannot handle constrained TSP yet') M = np.empty((n, n)) M.fill(np.nan) Cr_values = np.array(cr_values[mainCr]) isMax = objective[0][-1] in ('max', 'maximum') if isMax: Cr_values = -Cr_values for i, w in enumerate(EdgesDescriptors): node_in, node_out = EdgesCoords[i] M[node_in, node_out] = Cr_values[i] S = np.abs(Cr_values).sum() + 1.0 # TODO: check it M[np.isnan(M)] = S prob = P(lambda x: 0, np.zeros(n), iprint = 1) prob.f = lambda x: np.nan if not hasattr(prob, 'ff') else (prob.ff if isMax else -prob.ff) prob.M = dict([((i, j), M[i, j]) for i in range(n) for j in range(n) if i != j]) r = prob.solve(solver, **KW) xf = [nodes[j] for j in np.array(r.xf, int)] r.nodes = xf#.tolist() if self.start is not None: j = r.nodes.index(self.start) r.nodes = r.nodes[j:] + r.nodes[:j] if self.returnToStart: r.nodes += [r.nodes[0]] r.edges = [(r.nodes[i], r.nodes[i+1]) for i in range(n-1)] r.Edges = [(r.nodes[i], r.nodes[i+1], graph[r.nodes[i]][r.nodes[i+1]][0]) for i in range(n-1)] if self.returnToStart: r.edges.append((r.nodes[-2], r.nodes[0])) print(r.nodes[-1], r.nodes[0], type(r.nodes[-1]), type(r.nodes[0]), graph[2]) r.Edges.append((r.nodes[-2], r.nodes[0], graph[r.nodes[-2]][r.nodes[0]][0])) #r.xf = r.xk = r.nodes # TODO: Edges return r #TODO: fix ooarray lb/ub #u = np.array([1] + [fd.oovar(lb=2, ub=n) for i in range(n-1)]) u = fd.hstack((1, fd.oovars(n-1, lb=2, ub=n))) for i in range(1, u.size): u[i]('u' + str(i)) if is_interalg_raw_mode: for i in range(n-1): u[1+i].domain = np.arange(2, n+1) if interalg_gdp: assert len(x) == n x = fd.ooarray(x) # TODO: remove it when proper enum implementation in FD engine will be done for i in range(n): x[i]._init_domain = x[i].domain constraints.append(x[i]-x[i]._init_domain[-1] <= 0) x[i].domain = np.arange(int(2 ** np.ceil(np.log2(node_out_edges_num[i])))) # for i in range(n-1): # u[1+i]._init_domain = u[1+i].domain # constraints.append(u[1+i]-u[1+i]._init_domain[-1] <= 0) # u[1+i].domain = np.arange(u[1+i]._init_domain[0], u[1+i]._init_domain[0]+int(2 ** np.ceil(np.log2(u[1+i]._init_domain[-1]-u[1+i]._init_domain[0]+1)))) # u[1+i].ub = u[1+i].domain[-1] else: x = fd.oovars(m, domain=bool) # new m value for i in range(x.size): x[i]('x'+str(i)) # if init_graph_is_directed: dictFrom = dict([(node, []) for node in nodes]) dictTo = dict([(node, []) for node in nodes]) for i, edge in enumerate(EdgesCoords): From, To = edge dictFrom[From].append(i) dictTo[To].append(i) engine = fd.XOR # number of outcoming edges = 1 if not interalg_gdp: for node, edges_inds in dictFrom.items(): # !!!!!!!!!! TODO for interalg_raw_mode: and if all edges have sign similar to goal if 1 and is_interalg_raw_mode: c = engine([x[j] for j in edges_inds]) else: nEdges = fd.sum([x[j] for j in edges_inds]) c = nEdges >= 1 if self.allowRevisit else nEdges == 1 constraints.append(c) # number of incoming edges = 1 for node, edges_inds in dictTo.items(): if len(edges_inds) == 0: self.err('input graph has node %s that has no edge from any other node; solution is impossible' % node) if interalg_gdp: x_inds, x_vals = [], [] for elem in edges_inds: x_ind, x_val = edge_ind2x_ind_val[elem] x_inds.append(x_ind) x_vals.append(x_val) c = engine([(x[x_ind] == x_val)(tol = 0.5) for x_ind, x_val in zip(x_inds, x_vals)]) else: if 1 and is_interalg_raw_mode and engine == fd.XOR: c = engine([x[j] for j in edges_inds]) else: nEdges = fd.sum([x[j] for j in edges_inds]) c = nEdges >= 1 if self.allowRevisit else nEdges == 1 constraints.append(c) # MTZ for i, (I, J) in enumerate(EdgesCoords): ii, jj = node2index[I], node2index[J] if ii != 0 and jj != 0: if interalg_gdp: x_ind, x_val = edge_ind2x_ind_val[i] c = fd.ifThen((x[x_ind] == x_val)(tol=0.5), u[ii] - u[jj] <= - 1.0) elif is_interalg_raw_mode: c = fd.ifThen(x[i], u[ii] - u[jj] <= - 1.0)#u[jj] - u[ii] >= 1) else: c = u[ii] - u[jj] + 1 <= (n-1) * (1-x[i]) constraints.append(c) # handling objective(s) FF = [] for optCrName in usedValues: tmp = cr_values.get(optCrName, []) if len(tmp) == 0: self.err('seems like graph edgs have no attribute "%s" to perform optimization on it' % optCrName) elif len(tmp) != m: self.err('for optimization creterion "%s" at least one edge has no this attribute' % optCrName) if interalg_gdp: F = [] lc = 0 for X in x: domain = X._init_domain vals = [tmp[i] for i in range(lc, lc + domain.size)] lc += domain.size #F = sum(x) #F.append(fd.interpolator(domain, vals, k=1, s=0.00000001)(X)) F.append(fd.interpolator(domain, vals, k=1)(X)) #print(domain, vals) F = fd.sum(F) else: F = fd.sum(x*tmp) Funcs[optCrName] = F for obj in objective: FF.append((Funcs[obj[0]] if type(obj[0]) in (str, np.str_) else obj[0](Funcs), obj[1], obj[2])) for c in Cons: tmp = c(Funcs) if type(tmp) in (list, tuple, set): constraints += list(tmp) else: constraints.append(tmp) startPoint = {x:[0]*(m if not interalg_gdp else n)} startPoint.update(dict([(U, i+2) for i, U in enumerate(u[1:])])) p = P(FF if isMOP else FF[0][0], startPoint, constraints = constraints)#, fixedVars = fixedVars) for param in ('start', 'returnToStart'): KW.pop(param, None) r = p.solve(solver, **KW) if P != oo.MOP: r.ff = p.ff if interalg_gdp: x_ind_val2edge_ind = dict([(elem[1], elem[0]) for elem in edge_ind2x_ind_val.items()]) SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in [x_ind_val2edge_ind[(ind, x[ind](r))] for ind in range(n)]] else: SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in range(m) if r.xf[x[i]] == 1] if len(SolutionEdges) == 0: r.nodes = r.edges = r.Edges = [] return r S = dict([(elem[0], elem) for elem in SolutionEdges]) SE = [SolutionEdges[0]] for i in range(len(SolutionEdges)-1): SE.append(S[SE[-1][1]]) SolutionEdgesCoords = [(elem[0], elem[1]) for elem in SE] nodes = [edge[1] for edge in SolutionEdgesCoords] if self.start is not None: shift_ind = nodes.index(self.start) nodes = nodes[shift_ind:] + nodes[:shift_ind] if self.returnToStart: nodes.append(nodes[0]) edges = SolutionEdgesCoords[1:] + [SolutionEdgesCoords[0]] Edges = SE[1:] + [SE[0]] if self.start is not None: edges, Edges = edges[shift_ind:] + edges[:shift_ind], Edges[shift_ind:] + Edges[:shift_ind] if not self.returnToStart: edges, Edges = edges[:-1], Edges[:-1] r.nodes, r.edges, r.Edges = nodes, edges, Edges else: r.solution = 'for MOP see r.solutions instead of r.solution' tmp_c, tmp_v = r.solutions.coords, r.solutions.values # if interalg_gdp: # x_ind_val2edge_ind = dict([(elem[1], elem[0]) for elem in edge_ind2x_ind_val.items()]) # SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in [x_ind_val2edge_ind[(ind, x[ind](r))] for ind in range(n)]] # else: # SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in range(m) if r.xf[x[i]] == 1] if interalg_gdp: # default for MOP x_ind_val2edge_ind = dict([(elem[1], elem[0]) for elem in edge_ind2x_ind_val.items()]) r.solutions = MOPsolutions([[(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in [x_ind_val2edge_ind[(ind, x[ind](Point))] for ind in range(n)]] for Point in r.solutions]) else:# non-default r.solutions = MOPsolutions([[(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in range(m) if Point[x[i]] == 1] for Point in r.solutions]) r.solutions.values = tmp_v return r
def solve(self, *args, **kw): if len(args) > 1: self.err(''' incorrect number of arguments for solve(), must be at least 1 (solver), other must be keyword arguments''') if self.start is None and not self.returnToStart: self.err( 'for returnToStart=False mode you should provide start, other cases are unimplemented yet' ) solver = args[0] if len(args) != 0 else kw.get('solver', self.solver) KW = self.__init_kwargs.copy() KW.update(kw) objective = KW.get('objective', self.objective) if isinstance(objective, (list, tuple, set)): nCriteria = len(self.objective) if 3 * nCriteria != np.asarray(self.objective).size: objective = [ (objective[3 * i], objective[3 * i + 1], objective[3 * i + 2]) for i in range( int(round(np.asarray(self.objective).size / 3))) ] if len(objective) == 1: KW['fTol'], KW['goal'] = objective[0][1:] else: objective = [(self.objective, KW.get('fTol', getattr(self, 'fTol')), KW.get('goal', getattr(self, 'goal')))] nCriteria = len(objective) isMOP = nCriteria > 1 mainCr = objective[0][0] import FuncDesigner as fd, openopt as oo solverName = solver if type(solver) == str else solver.__name__ is_interalg = solverName == 'interalg' is_glp = solverName == 'sa' if is_glp: assert nCriteria == 1, 'you cannot solve multiobjective tsp by the solver' is_interalg_raw_mode = is_interalg and KW.get( 'dataHandling', oo.oosolver(solver).dataHandling) in ('auto', 'raw') KW.pop('objective', None) P = oo.MOP if nCriteria > 1 else oo.GLP if is_interalg else oo.MILP if not is_glp else oo.GLP import networkx as nx graph = self.graph # must be networkx Graph instance init_graph_is_directed = graph.is_directed() init_graph_is_multigraph = graph.is_multigraph() if not init_graph_is_multigraph or not init_graph_is_directed: graph = nx.MultiDiGraph( graph) #if init_graph_is_directed else nx.MultiGraph(graph) nodes = graph.nodes() edges = graph.edges() n = len(nodes) m = len(edges) node2index = dict([(node, i) for i, node in enumerate(nodes)]) # TODO: implement MOP with interalg_gdp mode (requires interpolation interval analysis for non-monotone funcs) interalg_gdp = 1 if not is_interalg: # or isMOP: # !!!!!!!!!!!!! TODO: add handling of MOP with interalg_gdp? interalg_gdp = 0 if interalg_gdp: x = [] edge_ind2x_ind_val = {} else: pass #x = fd.oovars(m, domain=bool) #cr_values = dict([(obj[0], []) for obj in objective]) cr_values = {} constraints = [] EdgesDescriptors, EdgesCoords = [], [] # mb rework it by successors etc? Funcs = {} Cons = KW.pop('constraints', []) if type(Cons) not in (list, tuple): Cons = [Cons] usedValues = getUsedValues(Cons) usedValues.update(getUsedValues([obj[0] for obj in objective])) MainCr = mainCr if type(mainCr) in (str, np.str_) else list(usedValues)[0] isMainCrMin = objective[0][2] in ('min', 'minimum') node_out_edges_num = [] for node in nodes: Edges = graph[node] node_out_edges_num.append(len(Edges)) out_nodes = Edges.keys() if len(out_nodes) == 0: self.err( 'input graph has node %s that does not lead to any other node; solution is impossible' % node) if init_graph_is_multigraph and not isMOP and type(mainCr) in [ str, np.str_ ]: W = {} for out_node in out_nodes: ww = list(Edges[out_node].values()) for w in ww: tmp = W.get(out_node, None) if tmp is None: W[out_node] = w continue th = tmp[mainCr] w_main_cr_val = w[mainCr] if isMainCrMin == (th > w_main_cr_val): W[out_node] = w Out_nodes, W = np.array(list(W.keys())), np.array( list(W.values())) else: W = np.hstack( [list(Edges[out_node].values()) for out_node in out_nodes]) Out_nodes = np.hstack([[out_node] * len(Edges[out_node]) for out_node in out_nodes]) if interalg_gdp: rr = np.array([w[MainCr] for w in W]) if isMainCrMin: rr = -rr elif objective[0][2] not in ('max', 'maximum'): self.err( 'unimplemented for fixed value goal in TSP yet, only min/max is possible for now' ) ind = rr.argsort() W = W[ind] Out_nodes = Out_nodes[ind] lc = 0 for i, w in enumerate(W): if interalg_gdp: edge_ind2x_ind_val[len(EdgesCoords)] = (len(x), lc) lc += 1 EdgesCoords.append((node, Out_nodes[i])) EdgesDescriptors.append(w) for key, val in w.items(): # for undirected: #if node2index[key] < node2index[out_node]: continue Val = val if self.returnToStart or node != self.start else 0 if key in cr_values: cr_values[key].append(Val) else: cr_values[key] = [Val] if interalg_gdp: x.append(fd.oovar(domain=np.arange(lc))) m = len(EdgesCoords) # new value if is_glp: if type(mainCr) not in (str, np.str_): self.err( 'for the solver "sa" only text name objectives are implemented (e.g. "time", "price")' ) if init_graph_is_multigraph: self.err('the solver "sa" cannot handle multigraphs yet') if len(Cons) != 0: self.err('the solver "sa" cannot handle constrained TSP yet') M = np.empty((n, n)) M.fill(np.nan) Cr_values = np.array(cr_values[mainCr]) isMax = objective[0][-1] in ('max', 'maximum') if isMax: Cr_values = -Cr_values for i, w in enumerate(EdgesDescriptors): node_in, node_out = EdgesCoords[i] M[node_in, node_out] = Cr_values[i] S = np.abs(Cr_values).sum() + 1.0 # TODO: check it M[np.isnan(M)] = S prob = P(lambda x: 0, np.zeros(n), iprint=1) prob.f = lambda x: np.nan if not hasattr(prob, 'ff') else ( prob.ff if isMax else -prob.ff) prob.M = dict([((i, j), M[i, j]) for i in range(n) for j in range(n) if i != j]) r = prob.solve(solver, **KW) xf = [nodes[j] for j in np.array(r.xf, int)] r.nodes = xf #.tolist() if self.start is not None: j = r.nodes.index(self.start) r.nodes = r.nodes[j:] + r.nodes[:j] if self.returnToStart: r.nodes += [r.nodes[0]] r.edges = [(r.nodes[i], r.nodes[i + 1]) for i in range(n - 1)] r.Edges = [(r.nodes[i], r.nodes[i + 1], graph[r.nodes[i]][r.nodes[i + 1]][0]) for i in range(n - 1)] if self.returnToStart: r.edges.append((r.nodes[-2], r.nodes[0])) print(r.nodes[-1], r.nodes[0], type(r.nodes[-1]), type(r.nodes[0]), graph[2]) r.Edges.append((r.nodes[-2], r.nodes[0], graph[r.nodes[-2]][r.nodes[0]][0])) #r.xf = r.xk = r.nodes # TODO: Edges return r #TODO: fix ooarray lb/ub #u = np.array([1] + [fd.oovar(lb=2, ub=n) for i in range(n-1)]) u = fd.hstack((1, fd.oovars(n - 1, lb=2, ub=n))) for i in range(1, u.size): u[i]('u' + str(i)) if is_interalg_raw_mode: for i in range(n - 1): u[1 + i].domain = np.arange(2, n + 1) if interalg_gdp: assert len(x) == n x = fd.ooarray(x) # TODO: remove it when proper enum implementation in FD engine will be done for i in range(n): x[i]._init_domain = x[i].domain constraints.append(x[i] - x[i]._init_domain[-1] <= 0) x[i].domain = np.arange( int(2**np.ceil(np.log2(node_out_edges_num[i])))) # for i in range(n-1): # u[1+i]._init_domain = u[1+i].domain # constraints.append(u[1+i]-u[1+i]._init_domain[-1] <= 0) # u[1+i].domain = np.arange(u[1+i]._init_domain[0], u[1+i]._init_domain[0]+int(2 ** np.ceil(np.log2(u[1+i]._init_domain[-1]-u[1+i]._init_domain[0]+1)))) # u[1+i].ub = u[1+i].domain[-1] else: x = fd.oovars(m, domain=bool) # new m value for i in range(x.size): x[i]('x' + str(i)) # if init_graph_is_directed: dictFrom = dict([(node, []) for node in nodes]) dictTo = dict([(node, []) for node in nodes]) for i, edge in enumerate(EdgesCoords): From, To = edge dictFrom[From].append(i) dictTo[To].append(i) engine = fd.XOR # number of outcoming edges = 1 if not interalg_gdp: for node, edges_inds in dictFrom.items(): # !!!!!!!!!! TODO for interalg_raw_mode: and if all edges have sign similar to goal if 1 and is_interalg_raw_mode: c = engine([x[j] for j in edges_inds]) else: nEdges = fd.sum([x[j] for j in edges_inds]) c = nEdges >= 1 if self.allowRevisit else nEdges == 1 constraints.append(c) # number of incoming edges = 1 for node, edges_inds in dictTo.items(): if len(edges_inds) == 0: self.err( 'input graph has node %s that has no edge from any other node; solution is impossible' % node) if interalg_gdp: x_inds, x_vals = [], [] for elem in edges_inds: x_ind, x_val = edge_ind2x_ind_val[elem] x_inds.append(x_ind) x_vals.append(x_val) c = engine([(x[x_ind] == x_val)(tol=0.5) for x_ind, x_val in zip(x_inds, x_vals)]) else: if 1 and is_interalg_raw_mode and engine == fd.XOR: c = engine([x[j] for j in edges_inds]) else: nEdges = fd.sum([x[j] for j in edges_inds]) c = nEdges >= 1 if self.allowRevisit else nEdges == 1 constraints.append(c) # MTZ for i, (I, J) in enumerate(EdgesCoords): ii, jj = node2index[I], node2index[J] if ii != 0 and jj != 0: if interalg_gdp: x_ind, x_val = edge_ind2x_ind_val[i] c = fd.ifThen((x[x_ind] == x_val)(tol=0.5), u[ii] - u[jj] <= -1.0) elif is_interalg_raw_mode: c = fd.ifThen(x[i], u[ii] - u[jj] <= -1.0) #u[jj] - u[ii] >= 1) else: c = u[ii] - u[jj] + 1 <= (n - 1) * (1 - x[i]) constraints.append(c) # handling objective(s) FF = [] for optCrName in usedValues: tmp = cr_values.get(optCrName, []) if len(tmp) == 0: self.err( 'seems like graph edgs have no attribute "%s" to perform optimization on it' % optCrName) elif len(tmp) != m: self.err( 'for optimization creterion "%s" at least one edge has no this attribute' % optCrName) if interalg_gdp: F = [] lc = 0 for X in x: domain = X._init_domain vals = [tmp[i] for i in range(lc, lc + domain.size)] lc += domain.size #F = sum(x) #F.append(fd.interpolator(domain, vals, k=1, s=0.00000001)(X)) F.append(fd.interpolator(domain, vals, k=1)(X)) #print(domain, vals) F = fd.sum(F) else: F = fd.sum(x * tmp) Funcs[optCrName] = F for obj in objective: FF.append( (Funcs[obj[0]] if type(obj[0]) in (str, np.str_) else obj[0](Funcs), obj[1], obj[2])) for c in Cons: tmp = c(Funcs) if type(tmp) in (list, tuple, set): constraints += list(tmp) else: constraints.append(tmp) startPoint = {x: [0] * (m if not interalg_gdp else n)} startPoint.update(dict([(U, i + 2) for i, U in enumerate(u[1:])])) p = P(FF if isMOP else FF[0][0], startPoint, constraints=constraints) #, fixedVars = fixedVars) for param in ('start', 'returnToStart'): KW.pop(param, None) r = p.solve(solver, **KW) if P != oo.MOP: r.ff = p.ff if interalg_gdp: x_ind_val2edge_ind = dict([ (elem[1], elem[0]) for elem in edge_ind2x_ind_val.items() ]) SolutionEdges = [ (EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in [x_ind_val2edge_ind[(ind, x[ind](r))] for ind in range(n)] ] else: SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in range(m) if r.xf[x[i]] == 1] if len(SolutionEdges) == 0: r.nodes = r.edges = r.Edges = [] return r S = dict([(elem[0], elem) for elem in SolutionEdges]) SE = [SolutionEdges[0]] for i in range(len(SolutionEdges) - 1): SE.append(S[SE[-1][1]]) SolutionEdgesCoords = [(elem[0], elem[1]) for elem in SE] nodes = [edge[1] for edge in SolutionEdgesCoords] if self.start is not None: shift_ind = nodes.index(self.start) nodes = nodes[shift_ind:] + nodes[:shift_ind] if self.returnToStart: nodes.append(nodes[0]) edges = SolutionEdgesCoords[1:] + [SolutionEdgesCoords[0]] Edges = SE[1:] + [SE[0]] if self.start is not None: edges, Edges = edges[shift_ind:] + edges[:shift_ind], Edges[ shift_ind:] + Edges[:shift_ind] if not self.returnToStart: edges, Edges = edges[:-1], Edges[:-1] r.nodes, r.edges, r.Edges = nodes, edges, Edges else: r.solution = 'for MOP see r.solutions instead of r.solution' tmp_c, tmp_v = r.solutions.coords, r.solutions.values # if interalg_gdp: # x_ind_val2edge_ind = dict([(elem[1], elem[0]) for elem in edge_ind2x_ind_val.items()]) # SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in [x_ind_val2edge_ind[(ind, x[ind](r))] for ind in range(n)]] # else: # SolutionEdges = [(EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in range(m) if r.xf[x[i]] == 1] if interalg_gdp: # default for MOP x_ind_val2edge_ind = dict([ (elem[1], elem[0]) for elem in edge_ind2x_ind_val.items() ]) r.solutions = MOPsolutions([[ (EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in [ x_ind_val2edge_ind[(ind, x[ind](Point))] for ind in range(n) ] ] for Point in r.solutions]) else: # non-default r.solutions = MOPsolutions([[ (EdgesCoords[i][0], EdgesCoords[i][1], EdgesDescriptors[i]) for i in range(m) if Point[x[i]] == 1 ] for Point in r.solutions]) r.solutions.values = tmp_v return r