1

我正在尝试在 Java 中使用 ojAlgo 库进行整数优化,但我无法为其提供我想要的目标函数。
我想最小化函数:(A - BX)'(A - BX),其中A是(nx 1)矩阵,B是(nxn)对角矩阵,X是(nx 1)矩阵优化变量。我希望 X 中的结果仅包含 integers 。
我能够设置一个不同的目标函数来最大化 BX 如何将其更改为 (A - BX)'(A - BX)?这是到目前为止的代码。

import org.apache.log4j.Logger;
import org.ojalgo.optimisation.Expression;
import org.ojalgo.optimisation.ExpressionsBasedModel;
import org.ojalgo.optimisation.Optimisation;
import org.ojalgo.optimisation.Variable;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.List;

public class AllocationOptimization {
    protected Logger log = Logger.getLogger(AllocationOptimization.class);

    // This is the objective function, since weight() is assigned to it. How to change this objective function to what I want?
    private List<Variable> makeVariables(HashMap<String, BigDecimal> matrixB) {
        List<Variable> result = new ArrayList<>();
        for (String assetName : matrixB.keySet()) {
            result.add(new Variable(assetName).weight(matrixB.get(assetName)));
        }
        return result;
    }

    private ExpressionsBasedModel createExpressionModel(List<Variable> variables) {
        final ExpressionsBasedModel model = new ExpressionsBasedModel();
        for (Variable v : variables) {
            model.addVariable(v);
        }
        return model;
    }

    private void addExpressionConstraints(ExpressionsBasedModel model, List<Variable> variables,
                                          HashMap<String, BigDecimal> matrixB,
                                          HashMap<String, BigDecimal> wantedAbsoluteSharesMap,
                                          BigDecimal idealTotalPrice) {
        Expression expression = model.addExpression("C1").upper(idealTotalPrice);
        int i = 0;
        for (String assetName : matrixB.keySet()) {
            expression.set(variables.get(i), matrixB.get(assetName));
            i += 1;
        }

        for (Variable v : variables) {
            long absShares = wantedAbsoluteSharesMap.get(v.getName()).longValue();
            v.lower((long) Math.max(0, 0.8 * absShares)).upper((long) Math.max(Math.max(0, 1.2 * absShares), 5));
        }
    }

    private void setIntegerSolving(ExpressionsBasedModel model) {
        for (Variable v : model.getVariables()) {
            v.setInteger(true);
        }
    }

    private HashMap<String, Long> getIntegerOptimizationResult(ExpressionsBasedModel model, HashMap<String, BigDecimal> matrixB) {
        Optimisation.Result result = model.maximise();

        return prepareResult(result, matrixB);
    }


    private HashMap<String, Long> prepareResult(Optimisation.Result result, HashMap<String, BigDecimal> matrixB) {
        int i = 0;
        HashMap<String, Long> optimizedResult = new HashMap<>();
        BigDecimal sumAssetPrices = new BigDecimal("0.0");

        for (String assetName : matrixB.keySet()) {
            long sharesCount = result.get(i).longValue();
            log.debug(assetName + ": " + sharesCount);
            optimizedResult.put(assetName, sharesCount);
            sumAssetPrices = sumAssetPrices.add(matrixB.get(assetName).multiply(BigDecimal.valueOf(sharesCount)));
            i += 1;
        }
        log.debug("Total assets value after converting shares to integer numbers: " + sumAssetPrices);

        return optimizedResult;
    }

    public HashMap<String, Long> optimizeSharesCount(HashMap<String, BigDecimal> constraint1,
                                                     HashMap<String, BigDecimal> matrixB,
                                                     BigDecimal constraint2) throws InputMismatchException {
        List<Variable> variableList = makeVariables(matrixB);
        ExpressionsBasedModel model = createExpressionModel(variableList);
        addExpressionConstraints(model, variableList, matrixB, constraint1, constraint2);
        setIntegerSolving(model);
        HashMap<String, Long> resultMap = getIntegerOptimizationResult(model, matrixB);

        return resultMap;

    }

    private HashMap<String, BigDecimal> createWantedAbsoluteSharesTest1() {
        HashMap<String, BigDecimal> absShares = new HashMap<>();
        absShares.put("NFLX", new BigDecimal("2"));
        absShares.put("MSFT", new BigDecimal("4"));
        absShares.put("GOOG", new BigDecimal("0"));
        absShares.put("AAPL", new BigDecimal("25"));

        return absShares;
    }

    private HashMap<String, BigDecimal> createAssetPricesMapTest1() {
        HashMap<String, BigDecimal> assetPrices = new HashMap<>();
        assetPrices.put("NFLX", new BigDecimal("601.06"));
        assetPrices.put("MSFT", new BigDecimal("296.75"));
        assetPrices.put("GOOG", new BigDecimal("2843.78"));
        assetPrices.put("AAPL", new BigDecimal("149.07"));

        return assetPrices;
    }


    public static void main(String[] args) {
        AllocationOptimization allocationOptimization = new AllocationOptimization();
        // For testing
        HashMap<String, BigDecimal> constr1 = allocationOptimization.createWantedAbsoluteSharesTest1();
        HashMap<String, BigDecimal> matrixB = allocationOptimization.createAssetPricesMapTest1();
        BigDecimal constr2 = new BigDecimal("5348.25");

        HashMap<String, Long> optimizedResult = null;
        try {
            optimizedResult = allocationOptimization.optimizeSharesCount(constr1, matrixB, constr2);
        } catch (Exception e) {
            e.printStackTrace();
        }
        assert optimizedResult != null;
        allocationOptimization.log.info("optimizedResult size: " + optimizedResult.size());
    }

}

4

2 回答 2

1

根据@apete 的评论,我修改了目标函数并添加了必要的约束。在这里为其他人发布我的解决方案。

private List<Variable> makeVariables(HashMap<String, BigDecimal> matrixB) {
    List<Variable> result = new ArrayList<>();
    for (String assetName : matrixB.keySet()) {
        result.add(new Variable(assetName));
    }
    return result;
}

private ExpressionsBasedModel createObjective(ExpressionsBasedModel model, List<Variable> variables,
                                              HashMap<String, BigDecimal> matrixA,
                                              HashMap<String, BigDecimal> matrixB) {
    // Anything and everything with that has a weight is summed up to form the objective function
    Expression objective = model.addExpression("Objective function").weight(BigDecimal.ONE);
    for (Variable variable : variables) {
        String assetName = variable.getName();
        objective.set(variable, new BigDecimal("-2").multiply(matrixA.get(assetName)).multiply(matrixB.get(assetName)));
        objective.set(variable, variable, matrixB.get(assetName).pow(2));
    }
    return model;
}

private void addExpressionConstraints(ExpressionsBasedModel model, List<Variable> variables,
                                      HashMap<String, BigDecimal> matrixB,
                                      HashMap<String, BigDecimal> wantedAbsoluteSharesMap,
                                      HashMap<String, BigDecimal> matrixA,
                                      BigDecimal idealTotalPrice, BigDecimal accountBalance) {
    Expression expression1 = model.addExpression("C1").upper(idealTotalPrice);
    for (Variable variable : variables) {
        expression1.set(variable, matrixB.get(variable.getName()));
    }

    for (Variable v : variables) {
        // No negative values constraint
        v.lower(0);
    }

    // This constraint is used to compensate for the constants arising in the quadratic objective function
    BigDecimal sumSquaresUserAllocation = new BigDecimal("0.0");
    for (String assetName : this.assetsList) {
        sumSquaresUserAllocation = sumSquaresUserAllocation.add(matrixA.get(assetName).pow(2));
    }

    Expression expression2 = model.addExpression("C2").upper(new BigDecimal("1.01").multiply(sumSquaresUserAllocation.multiply(new BigDecimal("-1"))));
    expression2.lower(new BigDecimal("0.99").multiply(sumSquaresUserAllocation.multiply(new BigDecimal("-1"))));
    for (Variable variable : variables) {
        String assetName = variable.getName();
        expression2.set(variable, new BigDecimal("-2").multiply(matrixA.get(assetName)).multiply(matrixB.get(assetName)));
        expression2.set(variable, variable, matrixB.get(assetName).pow(2));
    }
}

最后,我没有使用model.maximise()函数,而是使用model.minimise()最小化目标函数。

于 2021-11-02T21:33:59.333 回答
1

Variable您为:s分配了权重。这使它们成为目标函数的一部分。您还可以为Expression:s 分配权重。将任何/所有具有权重的事物相加以形成目标函数。

    Expression objective = model.addExpression("Whole Objective").weight(BigDecimal.ONE);
    for (Variable variableR : variables) {
        objective.set(variableR, linearParameter);
        for (Variable variableC : variables) {
            objective.set(variableR, variableC, quadraticParameter);
        }
    }

相当于:

    Expression objective = model.addExpression("Objective Part").weight(BigDecimal.ONE);
    for (Variable variableR : variables) {
        variableR.weight(linearParameter);
        for (Variable variableC : variables) {
            objective.set(variableR, variableC, quadraticParameter);
        }
    }
于 2021-09-29T06:09:29.280 回答