def solve(x0, risk_alphas, loadings, srisk, cost_per_trade=DEFAULT_COST, max_risk=0.01): N = len(x0) # don't hold no risk data (likely dead) lim = np.where(srisk.isnull(), 0.0, 1.0) loadings = loadings.fillna(0) srisk = srisk.fillna(0) risk_alphas = risk_alphas.fillna(0) with Model() as m: w = m.variable(N, Domain.inRange(-lim, lim)) longs = m.variable(N, Domain.greaterThan(0)) shorts = m.variable(N, Domain.greaterThan(0)) gross = m.variable(N, Domain.greaterThan(0)) m.constraint( "leverage_consistent", Expr.sub(gross, Expr.add(longs, shorts)), Domain.equalsTo(0), ) m.constraint("net_consistent", Expr.sub(w, Expr.sub(longs, shorts)), Domain.equalsTo(0.0)) m.constraint("leverage_long", Expr.sum(longs), Domain.lessThan(1.0)) m.constraint("leverage_short", Expr.sum(shorts), Domain.lessThan(1.0)) buys = m.variable(N, Domain.greaterThan(0)) sells = m.variable(N, Domain.greaterThan(0)) gross_trade = Expr.add(buys, sells) net_trade = Expr.sub(buys, sells) total_gross_trade = Expr.sum(gross_trade) m.constraint( "net_trade", Expr.sub(w, net_trade), Domain.equalsTo(np.asarray(x0)), # cannot handle series ) # add risk constraint vol = m.variable(1, Domain.lessThan(max_risk)) stacked = Expr.vstack(vol.asExpr(), Expr.mulElm(w, srisk.values)) stacked = Expr.vstack(stacked, Expr.mul(loadings.values.T, w)) m.constraint("vol-cons", stacked, Domain.inQCone()) alphas = risk_alphas.dot(np.vstack([loadings.T, np.diag(srisk)])) gain = Expr.dot(alphas, net_trade) loss = Expr.mul(cost_per_trade, total_gross_trade) m.objective(ObjectiveSense.Maximize, Expr.sub(gain, loss)) m.solve() result = pd.Series(w.level(), srisk.index) return result
def _update(self, clique_data, parent=None): for c in clique_data['cliques']: self.cliques[c['name']] = v = self.model.variable( c['name'], Domain.inRange(0.0, 1.0), Domain.isInteger() ) for img, cmd in product(c['images'], c['commands']): self.by_img_cmd[img,cmd].append(v) self._obj.append(Expr.mul(float(c['time']), v)) if parent is not None: self.model.constraint( 'c-%s-%s' % (c['name'], parent['name']), Expr.sub(v, self.cliques[parent['name']]), Domain.lessThan(0.0) ) for child in c['children']: self._update(child, c) for inter in clique_data['intersections']: self.model.constraint( 'iter-%d' % self._inter, Expr.add([self.cliques[i] for i in inter]), Domain.lessThan(1.0) ) self._inter += 1
def _update(self, clique_data, parent=None): for c in clique_data['cliques']: self.cliques[c['name']] = v = self.model.variable( c['name'], Domain.inRange(0.0, 1.0), Domain.isInteger()) for img, cmd in product(c['images'], c['commands']): self.by_img_cmd[img, cmd].append(v) self._obj.append(Expr.mul(float(c['time']), v)) if parent is not None: self.model.constraint( 'c-%s-%s' % (c['name'], parent['name']), Expr.sub(v, self.cliques[parent['name']]), Domain.lessThan(0.0)) for child in c['children']: self._update(child, c) for inter in clique_data['intersections']: self.model.constraint('iter-%d' % self._inter, Expr.add([self.cliques[i] for i in inter]), Domain.lessThan(1.0)) self._inter += 1
def markowitz_riskobjective(exp_ret, covariance_mat, bound): # define model with Model("mean var") as model: # set of n weights (unconstrained) weights = model.variable("weights", len(exp_ret), Domain.inRange(0.0, 1.0)) # standard deviation induced by covariance matrix stdev = __stdev(model, "std", weights, covariance_mat) # impose a bound on this standard deviation #mBound.upper(model, stdev, bound) model.constraint(stdev, Domain.lessThan(bound)) #mModel.maximise(model=model, expr=Expr.dot(exp_ret, weights)) model.objective(ObjectiveSense.Maximize, Expr.dot(exp_ret, weights)) # solve the problem model.solve() return np.array(weights.level())
z_2_a = m.variable('z_2_a', *binary) z_2_b = m.variable('z_2_b', *binary) z_2_c = m.variable('z_2_c', *binary) z_2_d = m.variable('z_2_d', *binary) z_3_b = m.variable('z_3_b', *binary) z_3_c = m.variable('z_3_c', *binary) z_3_d = m.variable('z_3_d', *binary) # Inclusion of an image and a command means that image must # use all command invocation from the clique. # For instance: # (1) z_1_a <= w_1 # (2) z_1_a <= y_a # (3) z_1_a >= w_1 + y_a - 1 m.constraint('c_1_a_1', Expr.sub(z_1_a, w_1), Domain.lessThan(0.0)) m.constraint('c_1_a_2', Expr.sub(z_1_a, y_a), Domain.lessThan(0.0)) m.constraint('c_1_a_3', Expr.sub(z_1_a, Expr.add([w_1, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_1_b_1', Expr.sub(z_1_b, w_1), Domain.lessThan(0.0)) m.constraint('c_1_b_2', Expr.sub(z_1_b, y_b), Domain.lessThan(0.0)) m.constraint('c_1_b_3', Expr.sub(z_1_b, Expr.add([w_1, y_b])), Domain.greaterThan(-1.0)) m.constraint('c_1_c', Expr.sub(0.0, Expr.add([w_1, y_c])), Domain.greaterThan(-1.0)) m.constraint('c_1_d', Expr.sub(0.0, Expr.add([w_1, y_d])), Domain.greaterThan(-1.0)) m.constraint('c_2_a_1', Expr.sub(z_2_a, w_2), Domain.lessThan(0.0))
# Each command must be run once for each image. m.constraint('c_1_a', Expr.add([x_1_a]), Domain.equalsTo(1.0)) m.constraint('c_1_b', Expr.add([x_1_b, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_2_a', Expr.add([x_2_a]), Domain.equalsTo(1.0)) m.constraint('c_2_b', Expr.add([x_2_b, x_23_bcd, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_2_c', Expr.add([x_2_c, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_2_d', Expr.add([x_2_d, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_3_b', Expr.add([x_3_b, x_23_bcd, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_3_c', Expr.add([x_3_c, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_3_d', Expr.add([x_3_d, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) # Add dependency constraints for sub-cliques. m.constraint('d_123_b_23_cd', Expr.sub(x_123_b, x_123_b_23_cd), Domain.greaterThan(0.0)) # Eliminated intersections between cliques. m.constraint('e1', Expr.add([x_23_bcd, x_123_b]), Domain.lessThan(1.0)) # Minimize resources required to construct all images. obj = [Expr.mul(c, x) for c, x in [ # Individual image/command pairs (r['A'], x_1_a), (r['B'], x_1_b), (r['A'], x_2_a), (r['B'], x_2_b), (r['C'], x_2_c), (r['D'], x_2_d), (r['B'], x_3_b), (r['C'], x_3_c), (r['D'], x_3_d), # Cliques (r['B'] + r['C'] + r['D'], x_23_bcd), (r['B'], x_123_b), (r['C'] + r['D'], x_123_b_23_cd), ]] m.objective('w', ObjectiveSense.Minimize, Expr.add(obj)) m.setLogHandler(sys.stdout)
# clique or incur its own cost. q_2_b = m.variable('q_2_b', *binary) q_2_c = m.variable('q_2_c', *binary) q_2_d = m.variable('q_2_d', *binary) q_3_b = m.variable('q_3_b', *binary) q_3_c = m.variable('q_3_c', *binary) q_3_d = m.variable('q_3_d', *binary) # Inclusion of an image and a command means that image must # use all command invocation from the clique. # For instance: # (1) z_1_a <= w_1 # (2) z_1_a <= y_a # (3) z_1_a >= w_1 + y_a - 1 m.constraint('c_1_a_1', Expr.sub(z_1_a, w_1), Domain.lessThan(0.0)) m.constraint('c_1_a_2', Expr.sub(z_1_a, y_a), Domain.lessThan(0.0)) m.constraint('c_1_a_3', Expr.sub(z_1_a, Expr.add([w_1, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_1_b_1', Expr.sub(z_1_b, w_1), Domain.lessThan(0.0)) m.constraint('c_1_b_2', Expr.sub(z_1_b, y_b), Domain.lessThan(0.0)) m.constraint('c_1_b_3', Expr.sub(z_1_b, Expr.add([w_1, y_b])), Domain.greaterThan(-1.0)) m.constraint('c_1_c', Expr.sub(0.0, Expr.add([w_1, y_c])), Domain.greaterThan(-1.0)) m.constraint('c_1_d', Expr.sub(0.0, Expr.add([w_1, y_d])), Domain.greaterThan(-1.0)) m.constraint('c_2_a_1', Expr.sub(z_2_a, w_2), Domain.lessThan(0.0)) m.constraint('c_2_a_2', Expr.sub(z_2_a, y_a), Domain.lessThan(0.0)) m.constraint('c_2_a_3', Expr.sub(z_2_a, Expr.add([w_2, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_2_b_1', Expr.sub(z_2_b, w_2), Domain.lessThan(0.0))
import json import numpy as np from mosek.fusion import Model, Domain, Expr, ObjectiveSense A = np.array([[-1., 3.], [4., -1.]]) b = np.array([4., 6.]) c = np.array([1., 1.]) with Model('ex1') as M: # variable x x = M.variable('x', 2, Domain.greaterThan(0.)) # constraints M.constraint('c1', Expr.dot(A[0, :], x), Domain.lessThan(b[0])) M.constraint('c2', Expr.dot(A[1, :], x), Domain.lessThan(b[1])) # objective function M.objective('obj', ObjectiveSense.Maximize, Expr.dot(c, x)) # solve M.solve() # solution sol = x.level() # report to json with open('ex1_output.json', 'w') as f: json.dump({ 'solution': {f'x[{i+1}]': xi for i, xi in enumerate(sol)}, 'cost': np.dot(sol, c), }, f)
z_2_a = m.variable('z_2_a', *binary) z_2_b = m.variable('z_2_b', *binary) z_2_c = m.variable('z_2_c', *binary) z_2_d = m.variable('z_2_d', *binary) z_3_b = m.variable('z_3_b', *binary) z_3_c = m.variable('z_3_c', *binary) z_3_d = m.variable('z_3_d', *binary) # Inclusion of an image and a command means that image must # use all command invocation from the clique. # For instance: # (1) z_1_a <= w_1 # (2) z_1_a <= y_a # (3) z_1_a >= w_1 + y_a - 1 m.constraint('c_1_a_1', Expr.sub(z_1_a, w_1), Domain.lessThan(0.0)) m.constraint('c_1_a_2', Expr.sub(z_1_a, y_a), Domain.lessThan(0.0)) m.constraint('c_1_a_3', Expr.sub(z_1_a, Expr.add([w_1, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_1_b_1', Expr.sub(z_1_b, w_1), Domain.lessThan(0.0)) m.constraint('c_1_b_2', Expr.sub(z_1_b, y_b), Domain.lessThan(0.0)) m.constraint('c_1_b_3', Expr.sub(z_1_b, Expr.add([w_1, y_b])), Domain.greaterThan(-1.0)) m.constraint('c_1_c', Expr.sub(0.0, Expr.add([w_1, y_c])), Domain.greaterThan(-1.0)) m.constraint('c_1_d', Expr.sub(0.0, Expr.add([w_1, y_d])), Domain.greaterThan(-1.0)) m.constraint('c_2_a_1', Expr.sub(z_2_a, w_2), Domain.lessThan(0.0)) m.constraint('c_2_a_2', Expr.sub(z_2_a, y_a), Domain.lessThan(0.0)) m.constraint('c_2_a_3', Expr.sub(z_2_a, Expr.add([w_2, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_2_b_1', Expr.sub(z_2_b, w_2), Domain.lessThan(0.0))
# Each command must be run once for each image. m.constraint('c_1_a', Expr.add([x_1_a, x_12_a]), Domain.equalsTo(1.0)) m.constraint('c_1_b', Expr.add([x_1_b, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_2_a', Expr.add([x_2_a, x_12_a]), Domain.equalsTo(1.0)) m.constraint('c_2_b', Expr.add([x_2_b, x_23_bcd, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_2_c', Expr.add([x_2_c, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_2_d', Expr.add([x_2_d, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_3_b', Expr.add([x_3_b, x_23_bcd, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_3_c', Expr.add([x_3_c, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_3_d', Expr.add([x_3_d, x_23_bcd, x_123_b_23_cd]), Domain.equalsTo(1.0)) # Add dependency constraints for sub-cliques. m.constraint('d_123_b_23_cd', Expr.sub(x_123_b, x_123_b_23_cd), Domain.greaterThan(0.0)) # Eliminated intersections between cliques. m.constraint('e1', Expr.add([x_23_bcd, x_123_b]), Domain.lessThan(1.0)) m.constraint('e2', Expr.add([x_12_a, x_123_b]), Domain.lessThan(1.0)) m.constraint('e3', Expr.add([x_12_a, x_23_bcd]), Domain.lessThan(1.0)) # Minimize resources required to construct all images. obj = [Expr.mul(c, x) for c, x in [ # Individual image/command pairs (r['A'], x_1_a), (r['B'], x_1_b), (r['A'], x_2_a), (r['B'], x_2_b), (r['C'], x_2_c), (r['D'], x_2_d), (r['B'], x_3_b), (r['C'], x_3_c), (r['D'], x_3_d), # Cliques (r['B'] + r['C'] + r['D'], x_23_bcd), (r['B'], x_123_b), (r['C'] + r['D'], x_123_b_23_cd), (r['A'], x_12_a)
q_2_b = m.variable('q_2_b', *binary) q_2_c = m.variable('q_2_c', *binary) q_2_d = m.variable('q_2_d', *binary) q_3_b = m.variable('q_3_b', *binary) q_3_c = m.variable('q_3_c', *binary) q_3_d = m.variable('q_3_d', *binary) # Inclusion of an image and a command means that image must # use all command invocation from the clique. # For instance: # (1) z_1_a <= w_1 # (2) z_1_a <= y_a # (3) z_1_a >= w_1 + y_a - 1 m.constraint('c_1_a_1', Expr.sub(z_1_a, w_1), Domain.lessThan(0.0)) m.constraint('c_1_a_2', Expr.sub(z_1_a, y_a), Domain.lessThan(0.0)) m.constraint('c_1_a_3', Expr.sub(z_1_a, Expr.add([w_1, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_1_b_1', Expr.sub(z_1_b, w_1), Domain.lessThan(0.0)) m.constraint('c_1_b_2', Expr.sub(z_1_b, y_b), Domain.lessThan(0.0)) m.constraint('c_1_b_3', Expr.sub(z_1_b, Expr.add([w_1, y_b])), Domain.greaterThan(-1.0)) m.constraint('c_1_c', Expr.sub(0.0, Expr.add([w_1, y_c])), Domain.greaterThan(-1.0)) m.constraint('c_1_d', Expr.sub(0.0, Expr.add([w_1, y_d])), Domain.greaterThan(-1.0)) m.constraint('c_2_a_1', Expr.sub(z_2_a, w_2), Domain.lessThan(0.0)) m.constraint('c_2_a_2', Expr.sub(z_2_a, y_a), Domain.lessThan(0.0)) m.constraint('c_2_a_3', Expr.sub(z_2_a, Expr.add([w_2, y_a])), Domain.greaterThan(-1.0)) m.constraint('c_2_b_1', Expr.sub(z_2_b, w_2), Domain.lessThan(0.0))
m.constraint('c_1_a', Expr.add([x_1_a, x_12_ab, x_123_b_12_a]), Domain.equalsTo(1.0)) m.constraint('c_1_b', Expr.add([x_1_b, x_12_ab, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_2_a', Expr.add([x_2_a, x_12_ab, x_123_b_12_a]), Domain.equalsTo(1.0)) m.constraint('c_2_b', Expr.add([x_2_b, x_12_ab, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_2_c', Expr.add([x_2_c, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_2_d', Expr.add([x_2_d, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_3_b', Expr.add([x_3_b, x_123_b]), Domain.equalsTo(1.0)) m.constraint('c_3_c', Expr.add([x_3_c, x_123_b_23_cd]), Domain.equalsTo(1.0)) m.constraint('c_3_d', Expr.add([x_3_d, x_123_b_23_cd]), Domain.equalsTo(1.0)) # Add dependency constraints for sub-cliques. m.constraint('d_123_b_12_a', Expr.sub(x_123_b, x_123_b_12_a), Domain.greaterThan(0.0)) m.constraint('d_123_b_23_cd', Expr.sub(x_123_b, x_123_b_23_cd), Domain.greaterThan(0.0)) # Eliminated intersections between cliques. m.constraint('e1', Expr.add([x_12_ab, x_123_b]), Domain.lessThan(1.0)) m.constraint('e2', Expr.add([x_123_b_12_a, x_123_b_23_cd]), Domain.lessThan(1.0)) # Minimize resources required to construct all images. obj = [Expr.mul(c, x) for c, x in [ # Individual image/command pairs (r['A'], x_1_a), (r['B'], x_1_b), (r['A'], x_2_a), (r['B'], x_2_b), (r['C'], x_2_c), (r['D'], x_2_d), (r['B'], x_3_b), (r['C'], x_3_c), (r['D'], x_3_d), # Cliques (r['A'] + r['B'], x_12_ab), (r['B'], x_123_b), (r['A'], x_123_b_12_a), (r['C'] + r['D'], x_123_b_23_cd), ]]
def solve(self, problem, saver): # Construct model. self.problem = problem self.model = model = Model() if self.time is not None: model.setSolverParam('mioMaxTime', 60.0 * int(self.time)) # x[i,s,c] = 1 if image i runs command c during stage s, 0 otherwise. self.x = x = {} for i, cmds in problem.images.items(): for s, c in product(problem.stages[i], cmds): x[i,s,c] = model.variable( 'x[%s,%s,%s]' % (i,s,c), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() ) # y[ip,iq,s,c] = 1 if images ip & iq have a shared path through stage # s by running command c during s, 0 otherwise. y = {} for (ip, iq), cmds in problem.shared_cmds.items(): for s, c in product(problem.shared_stages[ip, iq], cmds): y[ip,iq,s,c] = model.variable( 'y[%s,%s,%s,%s]' % (ip,iq,s,c), 1, Domain.inRange(0.0, 1.0), Domain.isInteger() # Domain.inRange(0.0, 1.0) ) # TODO: need to remove presolved commands so the heuristic doesn't try them. # TODO: Add a heuristic initial solution. # TODO: Presolving # Each image one command per stage, and each command once. for i in problem.images: for s in problem.stages[i]: model.constraint('c1[%s,%s]' % (i,s), Expr.add([x[i,s,c] for c in problem.images[i]]), Domain.equalsTo(1.0) ) for c in problem.images[i]: model.constraint('c2[%s,%s]' % (i,c), Expr.add([x[i,s,c] for s in problem.stages[i]]), Domain.equalsTo(1.0) ) # Find shared paths among image pairs. for (ip, iq), cmds in problem.shared_cmds.items(): for s in problem.shared_stages[ip,iq]: for c in cmds: model.constraint('c3[%s,%s,%s,%s]' % (ip,iq,s,c), Expr.sub(y[ip,iq,s,c], x[ip,s,c]), Domain.lessThan(0.0) ) model.constraint('c4[%s,%s,%s,%s]' % (ip,iq,s,c), Expr.sub(y[ip,iq,s,c], x[iq,s,c]), Domain.lessThan(0.0) ) if s > 1: lhs = Expr.add([y[ip,iq,s,c] for c in cmds]) rhs = Expr.add([y[ip,iq,s-1,c] for c in cmds]) model.constraint('c5[%s,%s,%s,%s]' % (ip,iq,s,c), Expr.sub(lhs, rhs), Domain.lessThan(0.0) ) if y: obj = Expr.add(y.values()) else: obj = 0.0 model.objective('z', ObjectiveSense.Maximize, obj) model.setLogHandler(sys.stdout) model.acceptedSolutionStatus(AccSolutionStatus.Feasible) model.solve() # Create optimal schedule. schedule = defaultdict(list) for i, stages in problem.stages.items(): for s in stages: for c in problem.images[i]: if x[i,s,c].level()[0] > 0.5: schedule[i].append(c) break saver(schedule)