0

Does anyone have suggestions or best practices for how to document the formulation of Pyomo models (mainly constraints) directly within the code? Ideally, I'd like to find a way to write the constraint math in LaTeX in the docstring of the helper functions that I use to define constraints and then have those docstrings picked up by Sphinx autodoc.

Currently, I'm using the @decorator style of writing Pyomo components, such as:

import pyomo.environ as pyo

class Model:
  def __init__(self, **kwargs):
    self.model = pyo.ConcreteModel()
    self.model.T = pyo.RangeSet(1, 24)
    self.model.x = pyo.Var(self.model.T, within=pyo.NonNegativeReals)

    @self.model.Constraint()
    def Example_Constraint(model):
      """This is the docstring that I would ideally be able to `autodoc`

      .. math ::
        \sum_{t \in T} x_{t} \geq 100
      """
      return sum(x[t] for t in self.model.T) >= 100

However, Sphinx cannot "see" inner functions, such as the functions used to construct Example_Constraint within the __init__ method.

Options:

  1. Move away from the @decorator syntax and have the helper functions as instance, static, or class methods that are called in the __init__ method (e.g., self.model.Test_Constraint = pyo.Constraint(self.model.T, rule=self.test_constraint_rule). The downside of this approach (and one of the reasons we originally adopted the @decorator syntax) was that the functions that it feels like duplication to define the Pyomo component (self.model.Example_Constraint) and a Python function to construct the component (self.test_constraint_rule).
  2. I've seen @GiorgioBalestieri's package https://github.com/GiorgioBalestrieri/pyomo-sphinx-docs, which works by pulling Pyomo components' doc. This seems like an OK option, but not ideal given that it's an experiment and light on formatting options.
  3. Other approaches that I don't know of?
  • Do you have strong reasons for stuffing the model inside a “Model” class and inside an `__init__`? If the model is a singleton, you could just make all of the function and constraint calls top-level. Defining constraint functions within an init seems to be a very odd construct. Other option is to just separate the math model from the code. I enumerate my constraints C1, C2, … and that ties in with a math document in LaTex or whatever that is easier to manage/read/think through in a separate document – AirSquid Sep 16 '22 at 03:25
  • Thanks—this is helpful food for thought. When you say “top-level”, do you mean outside a class structure entirely? I think we do want to have multiple model instances, so I think that was the original goal of encapsulating inside another `Model` class. Agreed that defining inner functions inside `__init__` seems weird. I inherited some of this code and wanted to see if others using Pyomo had a good approach before I started refactoring the code, with particular emphasis on capturing the math formulation. – Roderick Go Sep 17 '22 at 18:07

0 Answers0