Example #1
0
def minimum_variance(matrix):
    # Given the matrix of returns a (each column is a series of returns) this method
    # computes the weights for a minimum variance portfolio, e.g.

    # min   2-Norm[a*w]^2
    # s.t.
    #         w >= 0
    #     sum[w] = 1

    # This is the left-most point on the efficiency frontier in the classic Markowitz theory

    # build the model
    with Model("Minimum Variance") as model:
        # introduce the weight variable

        weights = model.variable("weights", matrix.shape[1],
                                 Domain.inRange(0.0, 1.0))
        # sum of weights has to be 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))
        # returns
        r = Expr.mul(Matrix.dense(matrix), weights)
        # compute l2_norm squared of those returns
        # minimize this l2_norm
        model.objective(ObjectiveSense.Minimize,
                        __l2_norm_squared(model, "2-norm^2(r)", expr=r))
        # solve the problem
        model.solve()
        # return the series of weights
        return np.array(weights.level())
Example #2
0
def lsq_pos(matrix, rhs):
    """
    min 2-norm (matrix*w - rhs)^2
    s.t. e'w = 1
           w >= 0
    """
    # define model
    with Model('lsqPos') as model:
        # introduce n non-negative weight variables
        weights = model.variable("weights", matrix.shape[1],
                                 Domain.inRange(0.0, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        v = __l2_norm(model,
                      "2-norm(res)",
                      expr=__residual(matrix, rhs, weights))

        # minimization of the residual
        model.objective(ObjectiveSense.Minimize, v)
        # solve the problem
        model.solve()

        return np.array(weights.level())
Example #3
0
def lsq_pos_l1_penalty(matrix, rhs, cost_multiplier, weights_0):
    """
    min 2-norm (matrix*w - rhs)** + 1-norm(cost_multiplier*(w-w0))
    s.t. e'w = 1
           w >= 0
    """
    # define model
    with Model('lsqSparse') as model:
        # introduce n non-negative weight variables
        weights = model.variable("weights", matrix.shape[1],
                                 Domain.inRange(0.0, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # sum of squared residuals
        v = __l2_norm_squared(model, "2-norm(res)**",
                              __residual(matrix, rhs, weights))

        # \Gamma*(w - w0), p is an expression
        p = Expr.mulElm(cost_multiplier, Expr.sub(weights, weights_0))

        cost = model.variable("cost", matrix.shape[1], Domain.unbounded())
        model.constraint(Expr.sub(cost, p), Domain.equalsTo(0.0))

        t = __l1_norm(model, 'abs(weights)', cost)

        # Minimise v + t
        model.objective(ObjectiveSense.Minimize,
                        __sum_weighted(1.0, v, 1.0, t))
        # solve the problem
        model.solve()

        return np.array(weights.level())
Example #4
0
def lsq_pos_l1_penalty(matrix, rhs, cost_multiplier, weights_0):
    """
    min 2-norm (matrix*w - rhs)** + 1-norm(cost_multiplier*(w-w0))
    s.t. e'w = 1
           w >= 0
    """
    # define model
    with Model('lsqSparse') as model:
        # introduce n non-negative weight variables
        weights = model.variable("weights", matrix.shape[1], Domain.inRange(0.0, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # sum of squared residuals
        v = __l2_norm_squared(model, "2-norm(res)**", __residual(matrix, rhs, weights))

        # \Gamma*(w - w0), p is an expression
        p = Expr.mulElm(cost_multiplier, Expr.sub(weights, weights_0))

        cost = model.variable("cost", matrix.shape[1], Domain.unbounded())
        model.constraint(Expr.sub(cost, p), Domain.equalsTo(0.0))

        t = __l1_norm(model, 'abs(weights)', cost)

        # Minimise v + t
        model.objective(ObjectiveSense.Minimize, __sum_weighted(1.0, v, 1.0, t))
        # solve the problem
        model.solve()

        return np.array(weights.level())
    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
Example #6
0
def minimum_variance(matrix):
    # Given the matrix of returns a (each column is a series of returns) this method
    # computes the weights for a minimum variance portfolio, e.g.

    # min   2-Norm[a*w]^2
    # s.t.
    #         w >= 0
    #     sum[w] = 1

    # This is the left-most point on the efficiency frontier in the classic Markowitz theory

    # build the model
    with Model("Minimum Variance") as model:
        # introduce the weight variable

        weights = model.variable("weights", matrix.shape[1], Domain.inRange(0.0, 1.0))
        # sum of weights has to be 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))
        # returns
        r = Expr.mul(Matrix.dense(matrix), weights)
        # compute l2_norm squared of those returns
        # minimize this l2_norm
        model.objective(ObjectiveSense.Minimize, __l2_norm_squared(model, "2-norm^2(r)", expr=r))
        # solve the problem
        model.solve()
        # return the series of weights
        return np.array(weights.level())
Example #7
0
def solve_sdp_program(A):
    assert A.ndim == 2
    assert A.shape[0] == A.shape[1]
    A = A.copy()
    n = A.shape[0]
    with Model('theta_2') as M:
        # variable
        X = M.variable('X', Domain.inPSDCone(n + 1))
        t = M.variable()
        # objective function
        M.objective(ObjectiveSense.Maximize, t)
        # constraints
        for i in range(n + 1):
            M.constraint(f'c{i}{i}', X.index(i, i), Domain.equalsTo(1.))
            if i == 0:
                continue
            M.constraint(f'c0,{i}', Expr.sub(X.index(0, i), t),
                         Domain.greaterThan(0.))
            for j in range(i + 1, n + 1):
                if A[i - 1, j - 1] == 0:
                    M.constraint(f'c{i},{j}', X.index(i, j),
                                 Domain.equalsTo(0.))
        # solution
        M.solve()
        X_sol = X.level()
        t_sol = t.level()
    t_sol = t_sol[0]
    theta = 1. / t_sol**2
    return theta
    def solve(self, problem, saver):
        # Construct model.
        self.problem = problem

        # Do recursive maximal clique detection.
        self.clique_data = clique_data = problem.cliques()
        self.model = model = Model()
        if self.time is not None:
            model.setSolverParam('mioMaxTime', 60.0  * int(self.time))

        # Each image needs to run all its commands. This keep track of
        # what variables run each command for each image.
        self.by_img_cmd = by_img_cmd = defaultdict(list)

        # Objective is the total cost of all the commands we run.
        self._obj = []

        # x[i,c] = 1 if image i incurs the cost of command c directly
        self.x = x = {}
        for img, cmds in problem.images.items():
            for cmd in cmds:
                name = 'x[%s,%s]' % (img, cmd)
                x[name] = v = self.model.variable(
                    name,
                    Domain.inRange(0.0, 1.0),
                    Domain.isInteger()
                )
                self._obj.append(Expr.mul(float(problem.commands[cmd]), v))
                by_img_cmd[img,cmd].append(v)

        # cliques[i] = 1 if clique i is used, 0 otherwise
        self.cliques = {}
        self._inter = 1
        self._update(clique_data)

        # Each image has to run each of its commands.
        for img_cmd, vlist in by_img_cmd.items():
            name = 'img-cmd-%s-%s' % img_cmd
            self.model.constraint(
                name,
                Expr.add(vlist),
                Domain.equalsTo(1.0)
            )

        model.objective('z', ObjectiveSense.Minimize, Expr.add(self._obj))
        model.setLogHandler(sys.stdout)
        model.acceptedSolutionStatus(AccSolutionStatus.Feasible)
        model.solve()

        # Translate the output of this to a schedule.
        schedule = defaultdict(list)
        self._translate(schedule, clique_data)
        for name, v in x.items():
            img, cmd = name.replace('x[','').replace(']','').split(',')
            if v.level()[0] > 0.5:
                schedule[img].append(cmd)
        saver(schedule)
 def Update_Z_Constr(self):
     self.Remove_Z_Constr()
     Z = self.model.getVariable('Z')
     if len(self.constr) == 1:
         for key, value in self.constr.items():  # only one iteration
             self.model.constraint('BB', Z.index(key),
                                   Domain.equalsTo(value))
     if len(self.constr) >= 2:
         expression = Expr.vstack(
             [Z.index(key) for key in self.constr.keys()])
         values = [value for key, value in self.constr.items()]
         self.model.constraint('BB', expression, Domain.equalsTo(values))
Example #10
0
 def __Update_Z_Constr(pure_model: Model, constr_z: Dict[int,
                                                         int]) -> Model:
     Z = pure_model.getVariable('Z')
     if len(constr_z) == 1:
         for key, value in constr_z.items():  # only one iteration
             pure_model.constraint('BB', Z.index(key),
                                   Domain.equalsTo(value))
     if len(constr_z) >= 2:
         expression = Expr.vstack([Z.index(key) for key in constr_z.keys()])
         values = [value for key, value in constr_z.items()]
         pure_model.constraint('BB', expression, Domain.equalsTo(values))
     return pure_model
Example #11
0
    def optimize_with_mosek(self, predicted, today):
        """
        使用Mosek来优化构建组合。在测试中Mosek比scipy的单纯形法快约18倍,如果可能请尽量使用Mosek。
        但是Mosek是一个商业软件,因此你需要一份授权。如果没有授权的话请使用scipy或optlang。
        """
        from mosek.fusion import Expr, Model, ObjectiveSense, Domain, SolutionError
        index_weight = self.index_weights.loc[today].fillna(0)
        index_weight = index_weight / index_weight.sum()
        stocks = list(predicted.index)

        with Model("portfolio") as M:
            x = M.variable("x", len(stocks),
                           Domain.inRange(0, self.constraint_config['stocks']))

            # 权重总和等于一
            M.constraint("sum", Expr.sum(x), Domain.equalsTo(1.0))

            # 控制风格暴露
            for factor_name, limit in self.constraint_config['factors'].items(
            ):
                factor_data = self.factor_data[factor_name].loc[today]
                factor_data = factor_data.fillna(factor_data.mean())
                index_exposure = (index_weight * factor_data).sum()
                stocks_exposure = factor_data.loc[stocks].values
                M.constraint(
                    factor_name, Expr.dot(stocks_exposure.tolist(), x),
                    Domain.inRange(index_exposure - limit,
                                   index_exposure + limit))

            # 控制行业暴露
            for industry_name, limit in self.constraint_config[
                    'industries'].items():
                industry_data = self.industry_data[industry_name].loc[
                    today].fillna(0)
                index_exposure = (index_weight * industry_data).sum()
                stocks_exposure = industry_data.loc[stocks].values
                M.constraint(
                    industry_name, Expr.dot(stocks_exposure.tolist(), x),
                    Domain.inRange(index_exposure - limit,
                                   index_exposure + limit))

            # 最大化期望收益率
            M.objective("MaxRtn", ObjectiveSense.Maximize,
                        Expr.dot(predicted.tolist(), x))
            M.solve()
            weights = pd.Series(list(x.level()), index=stocks)
            # try:
            #     weights = pd.Series(list(x.level()), index=stocks)
            # except SolutionError:
            #     raise RuntimeError("Mosek fail to find a feasible solution @ {}".format(str(today)))
        return weights[weights > 0]
Example #12
0
    def solve(self, problem, saver):
        # Construct model.
        self.problem = problem

        # Do recursive maximal clique detection.
        self.clique_data = clique_data = problem.cliques()
        self.model = model = Model()
        if self.time is not None:
            model.setSolverParam('mioMaxTime', 60.0 * int(self.time))

        # Each image needs to run all its commands. This keep track of
        # what variables run each command for each image.
        self.by_img_cmd = by_img_cmd = defaultdict(list)

        # Objective is the total cost of all the commands we run.
        self._obj = []

        # x[i,c] = 1 if image i incurs the cost of command c directly
        self.x = x = {}
        for img, cmds in problem.images.items():
            for cmd in cmds:
                name = 'x[%s,%s]' % (img, cmd)
                x[name] = v = self.model.variable(name,
                                                  Domain.inRange(0.0, 1.0),
                                                  Domain.isInteger())
                self._obj.append(Expr.mul(float(problem.commands[cmd]), v))
                by_img_cmd[img, cmd].append(v)

        # cliques[i] = 1 if clique i is used, 0 otherwise
        self.cliques = {}
        self._inter = 1
        self._update(clique_data)

        # Each image has to run each of its commands.
        for img_cmd, vlist in by_img_cmd.items():
            name = 'img-cmd-%s-%s' % img_cmd
            self.model.constraint(name, Expr.add(vlist), Domain.equalsTo(1.0))

        model.objective('z', ObjectiveSense.Minimize, Expr.add(self._obj))
        model.setLogHandler(sys.stdout)
        model.acceptedSolutionStatus(AccSolutionStatus.Feasible)
        model.solve()

        # Translate the output of this to a schedule.
        schedule = defaultdict(list)
        self._translate(schedule, clique_data)
        for name, v in x.items():
            img, cmd = name.replace('x[', '').replace(']', '').split(',')
            if v.level()[0] > 0.5:
                schedule[img].append(cmd)
        saver(schedule)
Example #13
0
def markowitz(exp_ret, covariance_mat, aversion):
    # define model
    with Model("mean var") as model:
        # set of n weights (unconstrained)
        weights = model.variable("weights", len(exp_ret), Domain.inRange(-np.infty, +np.infty))

        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # standard deviation induced by covariance matrix
        var = __variance(model, "var", weights, covariance_mat)

        model.objective(ObjectiveSense.Maximize, Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        model.solve()
        #mModel.maximise(model=model, expr=Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        return np.array(weights.level())
Example #14
0
def __linfty_norm(model, name, expr):
    t = model.variable(name, 1, Domain.unbounded())

    # (t, w_i) \in Q2
    for i in range(0, expr.size()):
        __quad_cone(model, t, expr.index(i))

    return t
Example #15
0
def __absolute(model, name, expr):
    t = model.variable(name, expr.size(), Domain.unbounded())

    # (t_i, w_i) \in Q2
    for i in range(0, int(expr.size())):
        __quad_cone(model, t.index(i), expr.index(i))

    return t
Example #16
0
def __linfty_norm(model, name, expr):
    t = model.variable(name, 1, Domain.unbounded())

    # (t, w_i) \in Q2
    for i in range(0, expr.size()):
        __quad_cone(model, t, expr.index(i))

    return t
Example #17
0
    def _solve_cvxopt_mosek(self):
        from mosek.fusion import Model, Domain, ObjectiveSense, Expr

        n, r = self.A
        with Model('L1 lp formulation') as model:
            model.variable('x', r, Domain.greaterThan(0.0))
            model.objective('l1 norm', ObjectiveSense.Minimize, Expr.dot())
            raise NotImplementedError
Example #18
0
def __absolute(model, name, expr):
    t = model.variable(name, expr.size(), Domain.unbounded())

    # (t_i, w_i) \in Q2
    for i in range(0, int(expr.size())):
        __quad_cone(model, t.index(i), expr.index(i))

    return t
Example #19
0
def markowitz(exp_ret, covariance_mat, aversion):
    # define model
    with Model("mean var") as model:
        # set of n weights (unconstrained)
        weights = model.variable("weights", len(exp_ret),
                                 Domain.inRange(-np.infty, +np.infty))

        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        # standard deviation induced by covariance matrix
        var = __variance(model, "var", weights, covariance_mat)

        model.objective(
            ObjectiveSense.Maximize,
            Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        model.solve()
        #mModel.maximise(model=model, expr=Expr.sub(Expr.dot(exp_ret, weights), Expr.mul(aversion, var)))
        return np.array(weights.level())
Example #20
0
def __l2_norm_squared(model, name, expr):
    """
    Given an expression (e.g. a vector) this returns the squared L2-norm of this vector as an expression.
    It also introduces an auxiliary variables. Mosek requires a name
    for any variable that is added to a model. The user has to specify this name explicitly.
    This requirement may disappear in future version of this API.
    """
    t = model.variable(name, 1, Domain.unbounded())
    __rotated_quad_cone(model, 0.5, t, expr)
    return t
Example #21
0
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())
Example #22
0
def __l2_norm_squared(model, name, expr):
    """
    Given an expression (e.g. a vector) this returns the squared L2-norm of this vector as an expression.
    It also introduces an auxiliary variables. Mosek requires a name
    for any variable that is added to a model. The user has to specify this name explicitly.
    This requirement may disappear in future version of this API.
    """
    t = model.variable(name, 1, Domain.unbounded())
    __rotated_quad_cone(model, 0.5, t, expr)
    return t
Example #23
0
def solve_sdp_program(W):
    assert W.ndim == 2
    assert W.shape[0] == W.shape[1]
    W = W.copy()
    n = W.shape[0]
    with Model('gw_max_cut') as M:
        W = Matrix.dense(W / 4.)
        J = Matrix.ones(n, n)
        # variable
        Y = M.variable('Y', Domain.inPSDCone(n))
        # objective function
        M.objective(ObjectiveSense.Maximize, Expr.dot(W, Expr.sub(J, Y)))
        # constraints
        for i in range(n):
            M.constraint(f'c_{i}', Y.index(i, i), Domain.equalsTo(1.))
        # solve
        M.solve()
        # solution
        Y_opt = Y.level()
    return np.reshape(Y_opt, (n, n))
Example #24
0
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())
Example #25
0
def lsq_ls(matrix, rhs):
    """
    min 2-norm (matrix*w - rhs)^2
    s.t. e'w = 1
    """
    # define model
    with Model('lsqPos') as model:
        weights = model.variable("weights", matrix.shape[1], Domain.inRange(-np.infty, +np.infty))

        # e'*w = 1
        model.constraint(Expr.sum(weights), Domain.equalsTo(1.0))

        v = __l2_norm(model, "2-norm(res)", expr=__residual(matrix, rhs, weights))

        # minimization of the residual
        model.objective(ObjectiveSense.Minimize, v)
        # solve the problem
        model.solve()

        return np.array(weights.level())
Example #26
0
def solve_sdp_program(A):
    assert A.ndim == 2
    assert A.shape[0] == A.shape[1]
    A = A.copy()
    n = A.shape[0]
    with Model('theta_1') as M:
        A = Matrix.dense(A)
        # variable
        X = M.variable('X', Domain.inPSDCone(n))
        # objective function
        M.objective(ObjectiveSense.Maximize,
                    Expr.sum(Expr.dot(Matrix.ones(n, n), X)))
        # constraints
        M.constraint(f'c1', Expr.sum(Expr.dot(X, A)), Domain.equalsTo(0.))
        M.constraint(f'c2', Expr.sum(Expr.dot(X, Matrix.eye(n))),
                     Domain.equalsTo(1.))
        # solution
        M.solve()
        sol = X.level()
    return sum(sol)
Example #27
0
def solve_sdp_program(W):
    assert W.ndim == 2
    assert W.shape[0] == W.shape[1]
    W = W.copy()
    n = W.shape[0]
    W = expand_matrix(W)
    with Model('gw_max_3_cut') as M:
        W = Matrix.dense(W / 3.)
        J = Matrix.ones(3*n, 3*n)
        # variable
        Y = M.variable('Y', Domain.inPSDCone(3*n))
        # objective function
        M.objective(ObjectiveSense.Maximize, Expr.dot(W, Expr.sub(J, Y)))
        # constraints
        for i in range(3*n):
            M.constraint(f'c_{i}{i}', Y.index(i, i), Domain.equalsTo(1.))
        for i in range(n):
            M.constraint(f'c_{i}^01', Y.index(i*3,   i*3+1), Domain.equalsTo(-1/2.))
            M.constraint(f'c_{i}^02', Y.index(i*3,   i*3+2), Domain.equalsTo(-1/2.))
            M.constraint(f'c_{i}^12', Y.index(i*3+1, i*3+2), Domain.equalsTo(-1/2.))
            for j in range(i+1, n):
                for a, b in product(range(3), repeat=2):
                    M.constraint(f'c_{i}{j}^{a}{b}-0', Y.index(i*3 + a, j*3 + b), Domain.greaterThan(-1/2.))
                    M.constraint(f'c_{i}{j}^{a}{b}-1', Expr.sub(Y.index(i*3 + a, j*3 + b), Y.index(i*3 + (a + 1) % 3, j*3 + (b + 1) % 3)), Domain.equalsTo(0.))
                    M.constraint(f'c_{i}{j}^{a}{b}-2', Expr.sub(Y.index(i*3 + a, j*3 + b), Y.index(i*3 + (a + 2) % 3, j*3 + (b + 2) % 3)), Domain.equalsTo(0.))
        # solution
        M.solve()
        Y_opt = Y.level()
    return np.reshape(Y_opt, (3*n,3*n))
Example #28
0
def solve_sdp_program(W, k):
    assert W.ndim == 2
    assert W.shape[0] == W.shape[1]
    W = W.copy()
    n = W.shape[0]
    with Model('fj_max_k_cut') as M:
        W = Matrix.dense((k - 1) / (2 * k) * W)
        J = Matrix.ones(n, n)
        # variable
        Y = M.variable('Y', Domain.inPSDCone(n))
        # objective function
        M.objective(ObjectiveSense.Maximize, Expr.dot(W, Expr.sub(J, Y)))
        # constraints
        for i in range(n):
            M.constraint(f'c_{i}', Y.index(i, i), Domain.equalsTo(1.))
            for j in range(i + 1, n):
                M.constraint(f'c_{i},{j}', Y.index(i, j),
                             Domain.greaterThan(-1 / (k - 1)))
        # solution
        M.solve()
        Y_opt = Y.level()
    return np.reshape(Y_opt, (n, n))
Example #29
0
    def __init__(self,name, 
                 foods, 
                 nutrients,
                 daily_allowance,
                 nutritive_value):
        Model.__init__(self,name)
        finished = False
        try:
          self.foods     = [ str(f) for f in foods ]
          self.nutrients = [ str(n) for n in nutrients ]
          self.dailyAllowance = array.array(daily_allowance, float)
          self.nutrientValue = DenseMatrix(nutritive_value).transpose()

          M = len(self.foods)
          N = len(self.nutrients)
          if len(self.dailyAllowance) != N:
              raise ValueError("Length of daily_allowance does not match "
                               "the number of nutrients")
          if self.nutrientValue.numColumns() != M:
              raise ValueError("Number of rows in nutrient_value does not "
                               "match the number of foods")
          if self.nutrientValue.numRows() != N:
              raise ValueError("Number of columns in nutrient_value does "
                               "not match the number of nutrients")
          
          self.__dailyPurchase = self.variable('Daily Purchase', 
                                               StringSet(self.foods), 
                                               Domain.greaterThan(0.0))
          self.__dailyNutrients = \
              self.constraint('Nutrient Balance',
                              StringSet(nutrients),
                              Expr.mul(self.nutrientValue,self.__dailyPurchase),
                              Domain.greaterThan(self.dailyAllowance))
          self.objective(ObjectiveSense.Minimize, Expr.sum(self.__dailyPurchase))
          finished = True
        finally:
          if not finished:
            self.__del__()
Example #30
0
    def __init__(self,name, 
                 foods, 
                 nutrients,
                 daily_allowance,
                 nutritive_value):
        Model.__init__(self,name)
        finished = False
        try:
          self.foods     = [ str(f) for f in foods ]
          self.nutrients = [ str(n) for n in nutrients ]
          self.dailyAllowance = numpy.array(daily_allowance, float)
          self.nutrientValue = Matrix.dense(nutritive_value).transpose()

          M = len(self.foods)
          N = len(self.nutrients)
          if len(self.dailyAllowance) != N:
              raise ValueError("Length of daily_allowance does not match "
                               "the number of nutrients")
          if self.nutrientValue.numColumns() != M:
              raise ValueError("Number of rows in nutrient_value does not "
                               "match the number of foods")
          if self.nutrientValue.numRows() != N:
              raise ValueError("Number of columns in nutrient_value does "
                               "not match the number of nutrients")
          
          self.__dailyPurchase = self.variable('Daily Purchase', 
                                               StringSet(self.foods), 
                                               Domain.greaterThan(0.0))
          self.__dailyNutrients = \
              self.constraint('Nutrient Balance',
                              StringSet(nutrients),
                              Expr.mul(self.nutrientValue,self.__dailyPurchase),
                              Domain.greaterThan(self.dailyAllowance))
          self.objective(ObjectiveSense.Minimize, Expr.sum(self.__dailyPurchase))
          finished = True
        finally:
          if not finished:
            self.__del__()
Example #31
0
    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
Example #32
0
    def __Declare_SpeedUp_Vars(self, COModel):
        n, N = self.n, 2 * self.m + 2 * self.n + len(self.roads)
        if self.co_params['speedup']['Tau'] is True:
            Tau = COModel.variable('Tau', 1, Domain.greaterThan(0.0))  # scalar
        else:
            Tau = COModel.variable('Tau', 1, Domain.unbounded())  # scalar

        if self.co_params['speedup']['Eta'] is True:
            Eta = COModel.variable('Eta', [n, n],
                                   Domain.inPSDCone(n))  # n by n matrix
        else:
            Eta = COModel.variable('Eta', [n, n],
                                   Domain.unbounded())  # n by n matrix

        if self.co_params['speedup']['W'] is True:
            W = COModel.variable('W', [N, N],
                                 Domain.inPSDCone(N))  # N by N matrix
        else:
            W = COModel.variable('W', [N, N],
                                 Domain.unbounded())  # N by N matrix
        return Tau, Eta, W
Example #33
0
def __quad_cone(model, expr1, expr2):
    model.constraint(Expr.vstack(expr1, expr2), Domain.inQCone())
Example #34
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('ex2') as M:
    # variable y
    y = M.variable('y', 2, Domain.greaterThan(0.))
    # constraints
    M.constraint('c1', Expr.dot(A.T[0, :], y), Domain.greaterThan(c[0]))
    M.constraint('c2', Expr.dot(A.T[1, :], y), Domain.greaterThan(c[1]))
    # objective function
    M.objective('obj', ObjectiveSense.Minimize, Expr.dot(b, y))
    # solve
    M.solve()
    # solution
    sol = y.level()

# report to json
with open('ex2_output.json', 'w') as f:
    json.dump(
        {
            'solution': {f'y[{i+1}]': yi
                         for i, yi in enumerate(sol)},
            'cost': np.dot(b, sol),
        }, f)
    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[1,c] = 1 if the master schedule has (null, c) in its first stage
        # x[s,c1,c2] = 1 if the master schedule has (c1, c2) in stage s > 1
        x = {}
        for s in problem.all_stages:
            if s == 1:
                # First arc in the individual image path.
                for c in problem.commands:
                    x[1,c] = model.variable(
                        'x[1,%s]' % c, 1,
                        Domain.inRange(0.0, 1.0),
                        Domain.isInteger()
                    )

            else:
                # Other arcs.
                for c1, c2 in product(problem.commands, problem.commands):
                    if c1 == c2:
                        continue
                    x[s,c1,c2] = model.variable(
                        'x[%s,%s,%s]' % (s,c1,c2), 1,
                        Domain.inRange(0.0, 1.0),
                        Domain.isInteger()
                    )

        smax = max(problem.all_stages)
        obj = [0.0]

        # TODO: deal with images that do not have the same number of commands.
        # t[s,c] is the total time incurred at command c in stage s
        t = {}
        for s in problem.all_stages:
            for c in problem.commands:
                t[s,c] = model.variable(
                    't[%s,%s]' % (c,s), 1,
                    Domain.greaterThan(0.0)
                )
                if s == 1:
                    model.constraint('t[1,%s]' % c,
                        Expr.sub(t[1,c], Expr.mul(float(problem.commands[c]), x[1,c])),
                        Domain.greaterThan(0.0)
                    )
                else:
                    rhs = [0.0]
                    for c1, coeff in problem.commands.items():
                        if c1 == c:
                            continue
                        else:
                            rhs = Expr.add(rhs, Expr.mulElm(t[s-1,c1], x[s,c1,c]))
                    model.constraint('t[%s,%s]' % (s,c),
                        Expr.sub(t[1,c], rhs),
                        Domain.greaterThan(0.0)
                    )

                    # Objective function = sum of aggregate  comand times
                    if s == smax:
                        obj = Expr.add(obj, t[s,c])

        # y[i,1,c] = 1 if image i starts by going to c
        # y[i,s,c1,c2] = 1 if image i goes from command c1 to c2 in stage s > 1
        y = {}
        for i, cmds in problem.images.items():
            for s in problem.stages[i]:
                if s == 1:
                    # First arc in the individual image path.
                    for c in cmds:
                        y[i,1,c] = model.variable(
                            'y[%s,1,%s]' % (i,c), 1,
                            Domain.inRange(0.0, 1.0),
                            Domain.isInteger()
                        )
                        model.constraint('x_y[i%s,1,c%s]' % (i,c),
                            Expr.sub(x[1,c], y[i,1,c]),
                            Domain.greaterThan(0.0)
                        )

                else:
                    # Other arcs.
                    for c1, c2 in product(cmds, cmds):
                        if c1 == c2:
                            continue
                        y[i,s,c1,c2] = model.variable(
                            'y[%s,%s,%s,%s]' % (i,s,c1,c2), 1,
                            Domain.inRange(0.0, 1.0),
                            Domain.isInteger()
                        )
                        model.constraint('x_y[i%s,s%s,c%s,c%s]' % (i,s,c1,c2),
                            Expr.sub(x[s,c1,c2], y[i,s,c1,c2]),
                            Domain.greaterThan(0.0)
                        )

            for c in cmds:
                # Each command is an arc destination exactly once.
                arcs = [y[i,1,c]]
                for c1 in cmds:
                    if c1 == c:
                        continue
                    arcs.extend([y[i,s,c1,c] for s in problem.stages[i][1:]])

                model.constraint('y[i%s,c%s]' % (i,c),
                    Expr.add(arcs),
                    Domain.equalsTo(1.0)
                )

                # Network balance equations (stages 2 to |stages|-1).
                # Sum of arcs in = sum of arcs out.
                for s in problem.stages[i][:len(problem.stages[i])-1]:
                    if s == 1:
                        arcs_in = [y[i,1,c]]
                    else:
                        arcs_in = [y[i,s,c1,c] for c1 in cmds if c1 != c]

                    arcs_out = [y[i,s+1,c,c2] for c2 in cmds if c2 != c]

                    model.constraint('y[i%s,s%s,c%s]' % (i,s,c),
                        Expr.sub(Expr.add(arcs_in), Expr.add(arcs_out)),
                        Domain.equalsTo(0.0)
                    )


        model.objective('z', ObjectiveSense.Minimize, Expr.add(x.values()))
#        model.objective('z', ObjectiveSense.Minimize, obj)
        model.setLogHandler(sys.stdout)
        model.acceptedSolutionStatus(AccSolutionStatus.Feasible)
        model.solve()

        # Create optimal schedule.
        schedule = defaultdict(list)
        for i, cmds in problem.images.items():
            for s in problem.stages[i]:
                if s == 1:
                    # First stage starts our walk.
                    for c in cmds:
                        if y[i,s,c].level()[0] > 0.5:
                            schedule[i].append(c)
                            break
                else:
                    # After that we know what our starting point is.
                    for c2 in cmds:
                        if c2 == c:
                            continue
                        if y[i,s,c,c2].level()[0] > 0.5:
                            schedule[i].append(c2)
                            c = c2
                            break

        saver(schedule)
Example #36
0
def __rotated_quad_cone(model, expr1, expr2, expr3):
    model.constraint(Expr.vstack(expr1, expr2, expr3), Domain.inRotatedQCone())
#
#    Image 3:
#        x_3_b = 0
#        x_3_c = 0
#        x_3_d = 0
#
#    Cliques:
#        x_23_bcd = 0
#        x_123_b = 1
#        x_123_b_23_cd = 1
#        x_12_a = 0

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Provide a variable for each image and command. This is 1 if the command
# is not run as part of a clique for the image.
x_1_a = m.variable('x_1_a', *binary)
x_1_b = m.variable('x_1_b', *binary)

x_2_a = m.variable('x_2_a', *binary)
x_2_b = m.variable('x_2_b', *binary)
x_2_c = m.variable('x_2_c', *binary)
x_2_d = m.variable('x_2_d', *binary)

x_3_b = m.variable('x_3_b', *binary)
x_3_c = m.variable('x_3_c', *binary)
x_3_d = m.variable('x_3_d', *binary)
Example #38
0
#
#    Image 3:
#        x_3_b = 0
#        x_3_c = 0
#        x_3_d = 0
#
#    Cliques:
#        x_23_bcd = 0
#        x_123_b = 1
#        x_123_b_23_cd = 1
#        x_12_a = 0

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Provide a variable for each image and command. This is 1 if the command
# is not run as part of a clique for the image.
x_1_a = m.variable('x_1_a', *binary)
x_1_b = m.variable('x_1_b', *binary)

x_2_a = m.variable('x_2_a', *binary)
x_2_b = m.variable('x_2_b', *binary)
x_2_c = m.variable('x_2_c', *binary)
x_2_d = m.variable('x_2_d', *binary)

x_3_b = m.variable('x_3_b', *binary)
x_3_c = m.variable('x_3_c', *binary)
x_3_d = m.variable('x_3_d', *binary)
Example #39
0
    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[1,c] = 1 if the master schedule has (null, c) in its first stage
        # x[s,c1,c2] = 1 if the master schedule has (c1, c2) in stage s > 1
        x = {}
        for s in problem.all_stages:
            if s == 1:
                # First arc in the individual image path.
                for c in problem.commands:
                    x[1, c] = model.variable('x[1,%s]' % c, 1,
                                             Domain.inRange(0.0, 1.0),
                                             Domain.isInteger())

            else:
                # Other arcs.
                for c1, c2 in product(problem.commands, problem.commands):
                    if c1 == c2:
                        continue
                    x[s, c1, c2] = model.variable('x[%s,%s,%s]' % (s, c1, c2),
                                                  1, Domain.inRange(0.0, 1.0),
                                                  Domain.isInteger())

        smax = max(problem.all_stages)
        obj = [0.0]

        # TODO: deal with images that do not have the same number of commands.
        # t[s,c] is the total time incurred at command c in stage s
        t = {}
        for s in problem.all_stages:
            for c in problem.commands:
                t[s, c] = model.variable('t[%s,%s]' % (c, s), 1,
                                         Domain.greaterThan(0.0))
                if s == 1:
                    model.constraint(
                        't[1,%s]' % c,
                        Expr.sub(t[1, c],
                                 Expr.mul(float(problem.commands[c]), x[1,
                                                                        c])),
                        Domain.greaterThan(0.0))
                else:
                    rhs = [0.0]
                    for c1, coeff in problem.commands.items():
                        if c1 == c:
                            continue
                        else:
                            rhs = Expr.add(
                                rhs, Expr.mulElm(t[s - 1, c1], x[s, c1, c]))
                    model.constraint('t[%s,%s]' % (s, c),
                                     Expr.sub(t[1, c], rhs),
                                     Domain.greaterThan(0.0))

                    # Objective function = sum of aggregate  comand times
                    if s == smax:
                        obj = Expr.add(obj, t[s, c])

        # y[i,1,c] = 1 if image i starts by going to c
        # y[i,s,c1,c2] = 1 if image i goes from command c1 to c2 in stage s > 1
        y = {}
        for i, cmds in problem.images.items():
            for s in problem.stages[i]:
                if s == 1:
                    # First arc in the individual image path.
                    for c in cmds:
                        y[i, 1, c] = model.variable('y[%s,1,%s]' % (i, c), 1,
                                                    Domain.inRange(0.0, 1.0),
                                                    Domain.isInteger())
                        model.constraint('x_y[i%s,1,c%s]' % (i, c),
                                         Expr.sub(x[1, c], y[i, 1, c]),
                                         Domain.greaterThan(0.0))

                else:
                    # Other arcs.
                    for c1, c2 in product(cmds, cmds):
                        if c1 == c2:
                            continue
                        y[i, s, c1, c2] = model.variable(
                            'y[%s,%s,%s,%s]' % (i, s, c1, c2), 1,
                            Domain.inRange(0.0, 1.0), Domain.isInteger())
                        model.constraint(
                            'x_y[i%s,s%s,c%s,c%s]' % (i, s, c1, c2),
                            Expr.sub(x[s, c1, c2], y[i, s, c1, c2]),
                            Domain.greaterThan(0.0))

            for c in cmds:
                # Each command is an arc destination exactly once.
                arcs = [y[i, 1, c]]
                for c1 in cmds:
                    if c1 == c:
                        continue
                    arcs.extend(
                        [y[i, s, c1, c] for s in problem.stages[i][1:]])

                model.constraint('y[i%s,c%s]' % (i, c), Expr.add(arcs),
                                 Domain.equalsTo(1.0))

                # Network balance equations (stages 2 to |stages|-1).
                # Sum of arcs in = sum of arcs out.
                for s in problem.stages[i][:len(problem.stages[i]) - 1]:
                    if s == 1:
                        arcs_in = [y[i, 1, c]]
                    else:
                        arcs_in = [y[i, s, c1, c] for c1 in cmds if c1 != c]

                    arcs_out = [y[i, s + 1, c, c2] for c2 in cmds if c2 != c]

                    model.constraint(
                        'y[i%s,s%s,c%s]' % (i, s, c),
                        Expr.sub(Expr.add(arcs_in), Expr.add(arcs_out)),
                        Domain.equalsTo(0.0))

        model.objective('z', ObjectiveSense.Minimize, Expr.add(x.values()))
        #        model.objective('z', ObjectiveSense.Minimize, obj)
        model.setLogHandler(sys.stdout)
        model.acceptedSolutionStatus(AccSolutionStatus.Feasible)
        model.solve()

        # Create optimal schedule.
        schedule = defaultdict(list)
        for i, cmds in problem.images.items():
            for s in problem.stages[i]:
                if s == 1:
                    # First stage starts our walk.
                    for c in cmds:
                        if y[i, s, c].level()[0] > 0.5:
                            schedule[i].append(c)
                            break
                else:
                    # After that we know what our starting point is.
                    for c2 in cmds:
                        if c2 == c:
                            continue
                        if y[i, s, c, c2].level()[0] > 0.5:
                            schedule[i].append(c2)
                            c = c2
                            break

        saver(schedule)
#        x_2_b = 0
#        x_2_c = 0
#        x_2_d = 0
#
#    Image 3:
#        x_3_b = 0
#        x_3_c = 0
#        x_3_d = 0
#
#    Cliques:
#        x_23_bcd = 1

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Provide a variable for each image and command. This is 1 if the command
# is not run as part of a clique for the image.
x_1_a = m.variable('x_1_a', *binary)
x_1_b = m.variable('x_1_b', *binary)

x_2_a = m.variable('x_2_a', *binary)
x_2_b = m.variable('x_2_b', *binary)
x_2_c = m.variable('x_2_c', *binary)
x_2_d = m.variable('x_2_d', *binary)

x_3_b = m.variable('x_3_b', *binary)
x_3_c = m.variable('x_3_c', *binary)
x_3_d = m.variable('x_3_d', *binary)
Example #41
0
def __quad_cone(model, expr1, expr2):
    model.constraint(Expr.vstack(expr1, expr2), Domain.inQCone())
Example #42
0
def __rotated_quad_cone(model, expr1, expr2, expr3):
    model.constraint(Expr.vstack(expr1, expr2, expr3), Domain.inRotatedQCone())
Example #43
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)
#        y_a = 0
#        y_b = 1
#        y_c = 0
#        y_d = 0
#
#    Interactions:
#        m_2 = 0
#        m_3 = 0
#        n_b = 1
#        n_c = 0
#        n_d = 0

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Variables to determine if we include commands in the clique.
y_a = m.variable('y_a', *binary)
y_b = m.variable('y_b', *binary)
y_c = m.variable('y_c', *binary)
y_d = m.variable('y_d', *binary)

# Variables to determine if we include images in the clique.
w_1 = m.variable('w_1', *binary)
w_2 = m.variable('w_2', *binary)
w_3 = m.variable('w_3', *binary)

# Variables to enforce relationships between y and w decisions.
z_1_a = m.variable('z_1_a', *binary)
z_1_b = m.variable('z_1_b', *binary)
Example #45
0
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 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)
#
#    Images:
#        w_1 = 0
#        w_2 = 1
#        w_3 = 1
#
#    Commands:
#        y_a = 0
#        y_b = 1
#        y_c = 1
#        y_d = 1

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Variables to determine if we include commands in the clique.
y_a = m.variable('y_a', *binary)
y_b = m.variable('y_b', *binary)
y_c = m.variable('y_c', *binary)
y_d = m.variable('y_d', *binary)

# Variables to determine if we include images in the clique.
w_1 = m.variable('w_1', *binary)
w_2 = m.variable('w_2', *binary)
w_3 = m.variable('w_3', *binary)

# Variables to enforce relationships between y and w decisions.
z_1_a = m.variable('z_1_a', *binary)
z_1_b = m.variable('z_1_b', *binary)
#
#    Image 2:
#        x_2_a = 1
#        x_2_b = 1
#        x_2_c = 1
#        x_2_d = 1
#
#    Image 3:
#        x_3_b = 1
#        x_3_c = 1
#        x_3_d = 1

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Provide a variable for each image and command. This is 1 if the command
# is not run as part of a clique for the image.
x_1_a = m.variable('x_1_a', *binary)
x_1_b = m.variable('x_1_b', *binary)

x_2_a = m.variable('x_2_a', *binary)
x_2_b = m.variable('x_2_b', *binary)
x_2_c = m.variable('x_2_c', *binary)
x_2_d = m.variable('x_2_d', *binary)

x_3_b = m.variable('x_3_b', *binary)
x_3_c = m.variable('x_3_c', *binary)
x_3_d = m.variable('x_3_d', *binary)
#        x_2_d = 0
#
#    Image 3:
#        x_3_b = 0
#        x_3_c = 0
#        x_3_d = 0
#
#    Cliques:
#        x_23_bcd = 0
#        x_123_b = 1
#        x_123_b_23_cd = 1

r = {'A': 5.0, 'B': 10.0, 'C': 7.0, 'D': 12.0}

m = Model()
binary = (Domain.inRange(0.0, 1.0), Domain.isInteger())

# Provide a variable for each image and command. This is 1 if the command
# is not run as part of a clique for the image.
x_1_a = m.variable('x_1_a', *binary)
x_1_b = m.variable('x_1_b', *binary)

x_2_a = m.variable('x_2_a', *binary)
x_2_b = m.variable('x_2_b', *binary)
x_2_c = m.variable('x_2_c', *binary)
x_2_d = m.variable('x_2_d', *binary)

x_3_b = m.variable('x_3_b', *binary)
x_3_c = m.variable('x_3_c', *binary)
x_3_d = m.variable('x_3_d', *binary)