Metadata-Version: 2.4
Name: ficomo
Version: 0.1.2
Summary: ficomo: a pyomo-like framework for the FICO xpress solver
Author-email: Nikita Kostiuchenko <nv.kostiuchenko@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/nkostiuchenko/ficomo
Project-URL: Repository, https://github.com/nkostiuchenko/ficomo
Project-URL: Issues, https://github.com/nkostiuchenko/ficomo/issues
Keywords: optimization
Classifier: Intended Audience :: Science/Research
Classifier: Natural Language :: English
Classifier: Operating System :: MacOS
Classifier: Operating System :: Unix
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Scientific/Engineering :: Mathematics
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: jsonpickle>=4.1.1
Requires-Dist: ray>=2.10.0
Requires-Dist: typer>=0.20.1
Requires-Dist: xpress>=9.8.0
Requires-Dist: xpresslibs>=9.8.0
Dynamic: license-file

![Logo](https://raw.githubusercontent.com/nkostiuchenko/ficomo/main/assets/logo-header.svg)

---

![Coverage](https://raw.githubusercontent.com/nkostiuchenko/ficomo/main/assets/coverage.svg)
[![PyPI](https://img.shields.io/pypi/v/ficomo)](https://pypi.org/project/ficomo/)
[![Python](https://img.shields.io/pypi/pyversions/ficomo)](https://pypi.org/project/ficomo/)
[![License](https://img.shields.io/pypi/l/ficomo)](LICENSE.md)


# ficomo: a pyomo-like framework for the FICO xpress solver

ficomo is a library that provides a set of tools for using the FICO xpress solver in the same way as pyomo. ficomo supports the following features:

## Features

✨ **Declarative syntax**: ficomo uses a declarative syntax for defining variables, expressions and constraints.

🚀 **Native support for FICO xpress**: ficomo provides a native interface to the xpress solver.

🔍 **Diagnostics**: ficomo provides tools for analyzing optimization problems, such as finding infeasible constraints, finding relaxations that will make the problem feasible, "force" solving an infeasible problem, etc.

⛓️ **Remote execution**: ficomo provides an easy way to run optimization problems on a remote executor node in both sync and async modes.

💾 **Save and load**: ficomo provides a way to save and load optimization problems and solutions without depending on xpress implementation details.

## Usage Example

Here's a basic example of using ficomo to solve a simple optimization problem. The model determines the optimal number of chairs and tables to produce given manufacturing time and storage space constraints, while maximizing profit.

```python
from ficomo.environ import Problem, Remote, SearchFor, Sense, var

USE_REMOTE = False # change to True to use remote execution
REMOTE_URL = None # None runs a local executor and connects to it

# Define decision variables
x1 = var(name="chairs", lb=0)  # number of chairs to produce
x2 = var(name="tables", lb=0)  # number of tables to produce

# Define objective: maximize profit
# Profit = 20 per chair + 30 per table
objective = 20 * x1 + 30 * x2

# Add constraints
# Resource constraints: time available for manufacturing
# Each chair takes 4 hours, each table takes 6 hours
# Total time available is 48 hours
time_constraint = 4 * x1 + 6 * x2 <= 48

# Storage space constraint:
# Each chair takes 0.2 sq m, each table takes 0.4 sq m
# Available space is 5 sq m
space_constraint = 0.2 * x1 + 0.4 * x2 <= 5.0

# Create the problem
variables = [x1, x2]
constraints = [time_constraint, space_constraint]
problem = Problem(variables, constraints, objective, sense=Sense.maximize)

if USE_REMOTE:
    # Solve the problem on a remote executor node
    with Remote(REMOTE_URL) as remote:
        solution = problem.to(remote).solve(search_for=SearchFor.optimal)

else:
    # Solve the problem localy
    solution = problem.solve(search_for=SearchFor.optimal)

# Print solution status
print(f"Solve status: {solution.solve_status!r}")
print(f"Solution status: {solution.solution_status!r}")

# Print solution
print(f"Optimal production plan: {solution.value({x1: x1, x2: x2})}")
print(f"Total profit: ${solution.value(objective)}")

# Output:
# Solve status: <SolveStatus.COMPLETED: 3>
# Solution status: <SolutionStatus.OPTIMAL: 1>
# Optimal production plan: {chairs: 12.0, tables: 0.0}
# Total profit: $240.0

# Save the problem to production-problem.fxp
problem.dump("production-problem.fxp")

# Save the solution to solution.fxs
# NOTE: the solution contains the problem
solution.dump("production-plan.fxs")

# Load the problem from production-problem.fxp
# problem = Problem.load("production-problem.fxp")

# Load the solution from solution.fxs
# solution = Solution.load("production-plan.fxs")
```
