{"id":16115267,"url":"https://github.com/embersarc/epigraph","last_synced_at":"2025-03-16T08:32:44.998Z","repository":{"id":37635720,"uuid":"275895718","full_name":"EmbersArc/Epigraph","owner":"EmbersArc","description":"A C++ interface to formulate and solve linear, quadratic and second order cone problems.","archived":false,"fork":false,"pushed_at":"2021-07-30T19:38:47.000Z","size":2916,"stargazers_count":155,"open_issues_count":5,"forks_count":16,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-02-27T05:56:14.498Z","etag":null,"topics":["eigen","eigen-library","numerical-optimization","qp","quadratic-programming","second-order-optimization","socp"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EmbersArc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-29T18:30:40.000Z","updated_at":"2024-12-03T19:27:03.000Z","dependencies_parsed_at":"2022-08-08T21:01:49.601Z","dependency_job_id":null,"html_url":"https://github.com/EmbersArc/Epigraph","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbersArc%2FEpigraph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbersArc%2FEpigraph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbersArc%2FEpigraph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EmbersArc%2FEpigraph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EmbersArc","download_url":"https://codeload.github.com/EmbersArc/Epigraph/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243807372,"owners_count":20350992,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eigen","eigen-library","numerical-optimization","qp","quadratic-programming","second-order-optimization","socp"],"created_at":"2024-10-09T20:18:20.814Z","updated_at":"2025-03-16T08:32:44.133Z","avatar_url":"https://github.com/EmbersArc.png","language":"C++","readme":"\u003cp align=\"center\"\u003e\n    \u003cimg src=\"img/logo.png\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://shields.io/\" alt=\"\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Version-0.4.2-green.svg\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://shields.io/\" alt=\"\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Maintained%3F-yes-green.svg\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://github.com/EmbersArc/Epigraph/blob/master/LICENSE\" alt=\"\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/License-MIT-blue.svg\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://travis-ci.org/github/EmbersArc/Epigraph\" alt=\"\"\u003e\n    \u003cimg src=\"https://api.travis-ci.org/EmbersArc/Epigraph.svg?branch=master\" /\u003e\u003c/a\u003e\n\u003ca href=\"https://codecov.io/gh/EmbersArc/Epigraph\" alt=\"\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/EmbersArc/Epigraph/branch/master/graph/badge.svg\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nEpigraph is a modern C++ interface to formulate and solve linear, quadratic and second order cone problems. It makes use of Eigen types and operator overloading for straightforward problem formulation.\n\n## Features\n* Flexible and intuitive way to formulate LPs, QPs and SOCPs\n* Dynamic parameters that can be changed without re-formulating the problem\n* Automatically clean up the problem and remove unused variables\n* Print the problem formulation and solver data for inspection\n\n## Dependencies\n\n* [Eigen](http://eigen.tuxfamily.org)\n\n## Supported Solvers\n\nThe solvers are included as submodules for convenience. Note that some solvers have more restrictive licenses which automatically override the Epigraph license when activated. Pass the listed argument to cmake during configuration to enable the solvers.\n\n### QP \n* [OSQP](https://github.com/oxfordcontrol/osqp) `-DENABLE_OSQP=TRUE`. Apache-2.0 License.\n\n### SOCP\n* [ECOS](https://github.com/embotech/ecos) `-DENABLE_ECOS=TRUE`. GPLv3 License.\n\n## Usage\n\n### CMake\nTo use Epigraph with a cmake project, simply enable the desired solvers, include the subdirectory and link the library.\n```\nset(ENABLE_OSQP TRUE)\nset(ENABLE_ECOS TRUE)\nadd_subdirectory(Epigraph)\ntarget_link_libraries(my_library epigraph)\n```\n\n### Documentation\n\nWhile the example below is likely enough to get you started, more explanation is provided below. The full reference can be found [here](https://embersarc.github.io/Epigraph/).\n\n### Example\n\n```cpp\n#include \"epigraph.hpp\"\n\n#include \u003ciostream\u003e\n\n// This example solves the portfolio optimization problem in QP form\n\nusing namespace cvx;\n\nint main()\n{\n    size_t n = 5; // Assets\n    size_t m = 2; // Factors\n\n    // Set up problem data.\n    double gamma = 0.5;          // risk aversion parameter\n    Eigen::VectorXd mu(n);       // vector of expected returns\n    Eigen::MatrixXd F(n, m);     // factor-loading matrix\n    Eigen::VectorXd D(n);        // diagonal of idiosyncratic risk\n    Eigen::MatrixXd Sigma(n, n); // asset return covariance\n\n    mu.setRandom();\n    F.setRandom();\n    D.setRandom();\n\n    mu = mu.cwiseAbs();\n    F = F.cwiseAbs();\n    D = D.cwiseAbs();\n    Sigma = F * F.transpose();\n    Sigma.diagonal() += D;\n\n    // Formulate QP.\n    OptimizationProblem qp;\n\n    // Declare variables with...\n    // addVariable(name) for scalars,\n    // addVariable(name, rows) for vectors and\n    // addVariable(name, rows, cols) for matrices.\n    VectorX x = qp.addVariable(\"x\", n);\n\n    // Available constraint types are equalTo(), lessThan(), greaterThan() and box()\n    qp.addConstraint(greaterThan(x, 0.));\n    qp.addConstraint(equalTo(x.sum(), 1.));\n\n    // Make mu dynamic in the cost function so we can change it later\n    qp.addCostTerm(x.transpose() * par(gamma * Sigma) * x - dynpar(mu).dot(x));\n\n    // Print the problem formulation for inspection\n    std::cout \u003c\u003c qp \u003c\u003c \"\\n\";\n\n    // Create and initialize the solver instance.\n    osqp::OSQPSolver solver(qp);\n\n    // Print the canonical problem formulation for inspection\n    std::cout \u003c\u003c solver \u003c\u003c \"\\n\";\n\n    // Solve problem and show solver output\n    const bool verbose = true;\n    solver.solve(verbose);\n\n    std::cout \u003c\u003c \"Solver message:  \" \u003c\u003c solver.getResultString() \u003c\u003c \"\\n\";\n    std::cout \u003c\u003c \"Solver exitcode: \" \u003c\u003c solver.getExitCode() \u003c\u003c \"\\n\";\n\n    // Call eval() to get the variable values\n    std::cout \u003c\u003c \"Solution:\\n\" \u003c\u003c eval(x) \u003c\u003c \"\\n\";\n\n    // Update data\n    mu.setRandom();\n    mu = mu.cwiseAbs();\n\n    // Solve again\n    // OSQP will warm start automatically\n    solver.solve(verbose);\n\n    std::cout \u003c\u003c \"Solution after changing the cost function:\\n\" \u003c\u003c eval(x) \u003c\u003c \"\\n\";\n}\n```\nSee the [tests](tests) for more examples, including the same problem in SOCP form.\n\n### Variables\nVariables are created by directly adding them to a problem:\n```cpp\n    OptimizationProblem qp;\n    cvx::Scalar scalar_var = qp.addVariable(\"x\");\n    cvx::VectorX vector_var = qp.addVariable(\"x\", n);\n    cvx::MatrixX matrix_var = qp.addVariable(\"x\", n, m);\n```\nThey contain the solution values after the problem has been solved successfully. Those values can be retrieved with the `eval` function, or by casting the value to a `double`.\n```cpp\n    double scalar_sol = cvx::eval(scalar_var);\n    Eigen::VectorXd vector_sol = cvx::eval(vector_var);\n    Eigen::MatrixXd matrix_sol = cvx::eval(matrix_var);\n```\n\n### Parameters\nThere are three kinds of parameters:\n#### Constant\nA value that can't be changed after instantiating the solver. Use the `par` function to turn scalars or Eigen types into constant parameters.\n#### Dynamic\nA value that *can* be changed after instantiating the solver. Use the `dynpar` function to turn scalars or Eigen types into dynamic parameters. Internally, this stores a pointer to the original data and will fetch the data each time the problem is solved. Important: Do not move or let this data go out of scope before the solver instance.\n#### Operation\nThis parameter type is created when using the operations `+`, `-`, `*` or `/` with dynamic parameters. This records the operations and will later execute them again to build the new problem based on the changed dynamic parameters. Using said operations with constant parameters will again yield constant parameters and not result in any additional computations.\n\n### Problem Formulation\nThe following terms may be passed to the constraint functions:\n\n| Function | Allowed expressions |\n| --- | --- |\n| `equalTo()`|`Affine == Affine` |\n| `lessThan()`| `Affine \u003c= Affine` or `Norm2 + Affine \u003c= Affine` (SOCP) |\n| `greaterThan()`| `Affine \u003e= Affine` or `Affine \u003e= Norm2 + Affine` (SOCP) |\n| `box()`| `Affine \u003c= Affine \u003c= Affine` |\n| `addCostTerm()`| `Affine` (SOCP) or `QuadForm + Affine` (QP) |\n\nWith the following expressions:\n\n| Expression | Form |\n| --- | --- |\n| `Affine` | `p1 * x1 + p2 * x2 + ... + c` |\n| `Norm2` | `(Affine1^2  + Affine2^2 + ...)^(1/2)` |\n| `QuadForm` | ``x' * P * x`` where `P` is Hermitian |\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fembersarc%2Fepigraph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fembersarc%2Fepigraph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fembersarc%2Fepigraph/lists"}