Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add structure to solve optimization problems #4

Merged
merged 26 commits into from
Apr 27, 2023
Merged

Conversation

S-Dafarra
Copy link
Member

An optimization problem can be set as follows

    @dataclasses.dataclass
    class SwitchVar(OptimizationObject):
        x: StorageType = default_storage_field(ContinuousVariable)
        y: StorageType = default_storage_field(ContinuousVariable)

        def __post_init__(self):
            self.x = np.zeros(1)
            self.y = np.zeros(1)

    a = 10
    new_problem = OptimizationProblem()
    new_variables = new_problem.generate_optimization_objects(SwitchVar())
    new_problem.add_expression(
        ExpressionType.minimize, a * new_variables.y * new_variables.y
    )
    new_problem.add_expression(
        ExpressionType.subject_to, new_variables.x + new_variables.y == a - 1
    ) 
    new_problem.add_expression(ExpressionType.minimize, new_variables.x == 5)
    output, cost_value = new_problem.solver().solve()

Note the line

new_problem.add_expression(ExpressionType.minimize, new_variables.x == 5)

Equalities can be cast into a cost. This might simplify the setting of tracking tasks.

@S-Dafarra S-Dafarra self-assigned this Mar 20, 2023
Copy link
Contributor

@traversaro traversaro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, some suggestions on the API but non blocking

@S-Dafarra
Copy link
Member Author

Another suggestion would be to add named arguments to have a scaling when passing a costraint and cast it into a cost.

@S-Dafarra
Copy link
Member Author

Another suggestion would be to add named arguments to have a scaling when passing a costraint and cast it into a cost.

Done in 109859c

@S-Dafarra S-Dafarra requested a review from traversaro March 24, 2023 15:26
@S-Dafarra
Copy link
Member Author

Friendly ping @traversaro @diegoferigo

@traversaro
Copy link
Contributor

Another suggestion would be to add named arguments to have a scaling when passing a costraint and cast it into a cost.

Done in 109859c

Great, thanks!

Copy link
Member

@diegoferigo diegoferigo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice @S-Dafarra 🚀 I like the direction. I left (too many) comments on this PR, feel free to include here what you think useful and -hopefully- address the nits/suggestions/python syntax enhancements in next ones. Approving regardless so you can move forward.

src/hippopt/base/optimization_solver.py Outdated Show resolved Hide resolved
src/hippopt/base/optimization_solver.py Show resolved Hide resolved
src/hippopt/base/optimization_solver.py Outdated Show resolved Hide resolved
src/hippopt/base/optimization_solver.py Outdated Show resolved Hide resolved
src/hippopt/base/optimization_solver.py Outdated Show resolved Hide resolved
Comment on lines +324 to +326
if isinstance(input_structure, OptimizationObject):
return self._generate_objects_from_instance(input_structure=input_structure)
return self._generate_objects_from_list(input_structure=input_structure)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit

Suggested change
if isinstance(input_structure, OptimizationObject):
return self._generate_objects_from_instance(input_structure=input_structure)
return self._generate_objects_from_list(input_structure=input_structure)
return (
self._generate_objects_from_instance if isinstance(input_structure, OptimizationObject)
else self._generate_objects_from_instance
)(input_structure=input_structure)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, but it does not work because it returns a function, not an object

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first () return a function selecting one among the two options, the second () passes to it the argument, this should work fine

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I apply the suggestion, this test fails with the error. Any suggestion?

test/test_optimization_problem.py:129 (test_opti_solver_with_parameters_and_lists)
class_or_instance = [MyTestVarAndPar(composite=MyTestVar(variable=array([0., 0., 0.])), parameter=array([0., 0., 0.])), MyTestVarAndPar(co...rray([0., 0., 0.])), MyTestVarAndPar(composite=MyTestVar(variable=array([0., 0., 0.])), parameter=array([0., 0., 0.]))]

    def fields(class_or_instance):
        """Return a tuple describing the fields of this dataclass.
    
        Accepts a dataclass or an instance of one. Tuple elements are of
        type Field.
        """
    
        # Might it be worth caching this, per class?
        try:
>           fields = getattr(class_or_instance, _FIELDS)
E           AttributeError: 'list' object has no attribute '__dataclass_fields__'

../../mambaforge/envs/hippopt/lib/python3.10/dataclasses.py:1196: AttributeError

During handling of the above exception, another exception occurred:

    def test_opti_solver_with_parameters_and_lists():
        problem = OptimizationProblem()
        initial_guess = []
        for _ in range(3):
            initial_guess.append(MyTestVarAndPar())
    
>       var = problem.generate_optimization_objects(input_structure=initial_guess)

test_optimization_problem.py:136: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../src/hippopt/base/optimization_problem.py:37: in generate_optimization_objects
    return self._solver.generate_optimization_objects(
../src/hippopt/base/opti_solver.py:346: in generate_optimization_objects
    return (
../src/hippopt/base/opti_solver.py:67: in _generate_objects_from_instance
    for field in dataclasses.fields(output):
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

class_or_instance = [MyTestVarAndPar(composite=MyTestVar(variable=array([0., 0., 0.])), parameter=array([0., 0., 0.])), MyTestVarAndPar(co...rray([0., 0., 0.])), MyTestVarAndPar(composite=MyTestVar(variable=array([0., 0., 0.])), parameter=array([0., 0., 0.]))]

    def fields(class_or_instance):
        """Return a tuple describing the fields of this dataclass.
    
        Accepts a dataclass or an instance of one. Tuple elements are of
        type Field.
        """
    
        # Might it be worth caching this, per class?
        try:
            fields = getattr(class_or_instance, _FIELDS)
        except AttributeError:
>           raise TypeError('must be called with a dataclass type or instance')
E           TypeError: must be called with a dataclass type or instance

../../mambaforge/envs/hippopt/lib/python3.10/dataclasses.py:1198: TypeError

src/hippopt/base/opti_solver.py Outdated Show resolved Hide resolved
src/hippopt/base/opti_solver.py Outdated Show resolved Hide resolved
test/test_optimization_problem.py Outdated Show resolved Hide resolved
src/hippopt/base/optimization_problem.py Outdated Show resolved Hide resolved
@S-Dafarra S-Dafarra force-pushed the optimizationStructure branch from aee7685 to fd41fc5 Compare March 31, 2023 10:09
@S-Dafarra
Copy link
Member Author

@diegoferigo I should have addressed your comments (except #4 (comment) where I am not sure how to continue).

I set the comments to resolved quite arbitrarily, so feel free to "Unresolve" the points that need some further discussion.

Let me know how you would like to proceed 😉

@S-Dafarra
Copy link
Member Author

I will proceed in merging this. Other open points will be addressed in future PRs.

@S-Dafarra S-Dafarra merged commit e3685c9 into main Apr 27, 2023
@S-Dafarra S-Dafarra deleted the optimizationStructure branch September 12, 2023 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants