2

I'd like to standardize a few cvxpy problems and use them in many places in my codebase. Here is a cleaned example:

from cvxpy import Variable, Parameter, Problem, Minimize

def problem_builder(n, ...)
    var = Variable(n)
    param = Parameter(n)

    costs = #Some complex convex function of var and param
    return Problem(Minimize(costs), constraints)

prob = problem_builder(4)
prob.var.value = [1,2,3,4]  #???
prob.parameters()[0] = [1,2,3,4]  #Ugly ???

I could create var and param outside the function and then pass them around with the problem but that seems awkward.

Can I access var and param somehow from prob? What are the best practices around using the same cvxpy Problem across multiple modules?

rhaskett
  • 1,864
  • 3
  • 29
  • 48
  • Make it a class (object-oriented programming). The usual, minimal methods are probably something like ```build_model``` and ```solve```, sometimes ```preprocess``` (and ```update_parameters```). Yes, there are crazy things like [function-attributes](https://stackoverflow.com/questions/338101/python-function-attributes-uses-and-abuses), but i won't do that. – sascha Jun 07 '18 at 19:50
  • Sorry, it was unclear but Problem is a class in CVXPY and it has a solve() function. Usually, as you mention, in OOP it would have some way of accessing used variables and parameters. – rhaskett Jun 07 '18 at 19:55
  • That's not shown in your code. So edit it, show what you tried and what doesn't work. – sascha Jun 07 '18 at 19:56
  • Just edited that. – rhaskett Jun 07 '18 at 19:56
  • I suppose I could wrap (inherit) the cvxpy Problem class into my own class, seems like it is not how it is designed to be used though. – rhaskett Jun 07 '18 at 20:01
  • I recommend(ed) to create a problem-specific class, containing methods *builder* and it's own *update_params* and *solve*. That's as clean as it gets! What you want is probably not possible, and even if, scary. Problems are immutable (in genral)! You need to keep some reference to the param-object. That, a class would do. – sascha Jun 07 '18 at 20:01
  • And problem's [variable-accessor method](https://github.com/cvxgrp/cvxpy/blob/master/cvxpy/problems/problem.py#L137) does not look to be competitive to a clean class-based approach. If you define two vars x and y, build your problem and access problem's variables through ```problem.variables()```, you will get something like: ```[Variable((20,), Variable((1,)))]``` which has lost a lot of information (and the function uses ```set``` (ordering kind of random)). – sascha Jun 07 '18 at 20:12
  • I get what you are saying. I created a class with a cvxpy Problem as a attribute as well as the Variable(s) and Parameter(s). It seemed better in the end then inheritance. If you write up an outline of a solution (maybe you have cleaner thoughts), I'll give you credit. – rhaskett Jun 07 '18 at 20:52
  • Why don't add a short answer yourself with what you did. I think it's less trouble (more connected to your use-case; less abstract). – sascha Jun 07 '18 at 20:52

2 Answers2

2

Following sascha's comments on creating a wrapper class...

from cvxpy import Variable, Parameter, Problem, Minimize

class MyProblem(self, n, ...):
    self._var = Variable(n)
    self.param = Parameter(n)

    costs = #Some complex convex function of var and param
    self._problem = Problem(Minimize(costs), constraints)

    def solve(self):
        self._problem.solve()
        return self._target

problem = MyProblem(4, ...)
for param_value in param_values:
    problem.param.value = param_value
    answer = problem.solve()

This allows for a sweep through the parameter param while standardizing the problem design.

rhaskett
  • 1,864
  • 3
  • 29
  • 48
2

You can now access the parameters and variables as a dictionary using:

param = cp.Parameter(name='paramname')
problem.param_dict

and

var = cp.Variable(name='varname')
problem.var_dict

where the parameter/variable names are the keys of the dictionary

jdkworld
  • 58
  • 1
  • 6