FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Capital budgeting - Using multi-objective optimization

Description
Capital budgeting example, solved using three multi-objective approaches:
  • Lexicographic approach, solving first to minimize capital expended and second to maximize return
  • Blended approach, solving a weighted combination of both objectives simultaneously
  • Lexicographic approach, with the objective priorities reversed
The model version Capbgt2l demonstrates the formuation of logical constraints.

capbgt_cpp.zip[download all files]

Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
CapitalBudgeting.cpp[download]
Capbgt2l.cpp[download]





Capbgt2l.cpp

#include <xpress.hpp>
#include <stdexcept>  // For throwing exceptions

using namespace xpress;
using namespace xpress::objects;
using xpress::objects::utils::sum;

/*
 * Capital budgeting problem. Illustrates: Logical conditions,
   Formulation using logic constraints
 */

// A project.
class Project {
public:
    const std::string name;     // The name of this project.
    const double payout;        // Payout for the project.
    const double investment;    // Capital investment for the project.
    const int personnel;        // Number of personnel required for the project.

    Project(std::string name, double payout, double investment, int personnel)
        : name(name), payout(payout), investment(investment), personnel(personnel) {}

    // For printing
    std::string toString() const {
        return name;
    }
};

// The projects used in this example.
const std::vector<Project> projectArray = {
    Project("Alpha",    124000.0,   104000.0,   22),
    Project("Beta",     74000.0,    53000.0,    12),
    Project("Gamma",    42000.0,    29000.0,    7),
    Project("Delta",    188000.0,   187000.0,   36),
    Project("Epsilon",  108000.0,   98000.0,    24),
    Project("Zeta",     56000.0,    32000.0,    10),
    Project("Eta",      88000.0,    75000.0,    20),
    Project("Theta",    225000.0,   200000.0,   41)
};

// The resource constraints used in this example.
const double budget = 478000.0;
const int workforce = 106;

int main() {
    try {
        // Create a problem instance with or without verbose messages printed to Console
        XpressProblem prob;
        // prob.callbacks.addMessageCallback(XpressProblem::console);

        /* VARIABLES */

        // Whether each project should be invested in or not
        std::vector<Variable> x = prob.addVariables(static_cast<int>(projectArray.size()))
                .withType(ColumnType::Binary)
                .withName("x%d")
                .toArray();

        /* RESOURCE AVAILABILITY CONSTRAINTS */

        // Investment limit: sum of investments of all undertaken projects should not exceed budget
        Expression requiredInvestment = sum(static_cast<int>(projectArray.size()), [&](int i) {
            return x[i].mul(projectArray[i].investment);
        });
        Inequality investmentLimit = prob.addConstraint(requiredInvestment <= budget);

        // Workforce limit: sum of personnel committed of all undertaken projects should not exceed workforce
        LinExpression requiredWorkforce = LinExpression::create();
        for (std::size_t i=0; i<projectArray.size(); i++) {
            requiredWorkforce.addTerm(x[i], projectArray[i].personnel);
        }
        Inequality workforceLimit = prob.addConstraint(requiredWorkforce <= workforce);

        // Project alpha can only be done if both gamma and zeta happen
        prob.addConstraint(x[0] <= x[2]);
        prob.addConstraint(x[0] <= x[5]);

        // Project zeta can only be done if project epsilon happens
        prob.addConstraint(x[5] <= x[4]);

        // Projects alpha and beta as well as gamma and delta can only happen together
        prob.addConstraint(x[0] == x[1]);
        prob.addConstraint(x[2] == x[3]);

        // Exactly one of those pairs should be invested in, i.e., if project alpha is
        // performed, neither gamma nor delta can be invested in, and if project alpha
        // does not happen, then projects gamma and delta have to be performed
        prob.addConstraint(x[0].ifThen(sum(x[2], x[3]) == 0.0));
        prob.addConstraint(x[0].ifNotThen(sum(x[2], x[3]) == 2.0));

        /* OBJECTIVE */

        // Objective function: sum of payouts of all undertaken projects
        Expression totalProfit = sum(static_cast<int>(projectArray.size()), [&](int i) {
            return x[i].mul(projectArray[i].payout);
        });
        prob.setObjective(totalProfit, xpress::ObjSense::Maximize);

        /* INSPECT, SOLVE & PRINT */

        // Dump the problem to disk so that we can inspect it.
        prob.writeProb("capbgt2l.lp");

        // Solve
        prob.optimize();

        // Check the solution status
        if (prob.attributes.getSolStatus() != SolStatus::Optimal && prob.attributes.getSolStatus() != SolStatus::Feasible) {
            std::ostringstream oss; oss << prob.attributes.getSolStatus(); // Convert xpress::SolStatus to String
            throw std::runtime_error("Optimization failed with status " + oss.str());
        }

        // Get the solution and print it
        std::vector<double> sol = prob.getSolution();
        std::cout << std::endl << "*** Solution ***" << std::endl;
        std::cout << "Objective: " << prob.attributes.getObjVal() << std::endl;;

        // Print the interesting slacks
        std::cout << "Remaining Budget: " << investmentLimit.getSlack() << " (out of " << budget << ")" << std::endl;
        std::cout << "Remaining Workers: " << workforceLimit.getSlack() << " (out of " << workforce << ")" << std::endl;

        // Print out the variables
        for (std::size_t i = 0; i < projectArray.size(); ++i) {
            if (x[i].getValue(sol) > 0.0) {
                std::cout << "Undertaking project " << projectArray[i].toString() << std::endl;
            }
        }
        return 0;
    }
    catch (std::exception& e) {
        std::cout << "Exception: " << e.what() << std::endl;
        return -1;
    }
}

Back to examples browserPrevious exampleNext example