-
Notifications
You must be signed in to change notification settings - Fork 48
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
Readme update and trapezoidal integration of cost function #458
Conversation
first iteration
Still need to address some challenges:
|
still a weird bad file descriptor |
@pariterre, I think it started to be something now. I have to finalize the tests for the targets for each use case. Let me know if I need to modify something in the core. |
@Ipuch please update your branch to master |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 4 of 10 files at r1, 3 of 6 files at r2, 7 of 7 files at r3, 1 of 1 files at r4, all commit messages.
Reviewable status: all files reviewed, 21 unresolved discussions (waiting on @Ipuch)
README.md
line 329 at r3 (raw file):
To solve the ocp, you simply have to call the `solve()` method of the `ocp` class ```python solver=Solver.IPOPT(show_online_optim=True)
"r = S"
bioptim/__init__.py
line 184 at r3 (raw file):
VariableType, SolutionIntegrator, IntegralApproximation,
I feel that "Integral" is the value of an "Integration", but I may be wrong... Inuitively it makes more sense to me to call it "IntegrationApproximation" as it is the process of integration which is approximate
bioptim/examples/getting_started/pendulum.py
line 111 at r3 (raw file):
# Custom plots ocp.add_plot_penalty(CostType.OBJECTIVES)
Please do not change, apart for good reasons, the behavior of example. If you want to try something you can create a "sandbox" folder and it will automatically be ignore for your push
bioptim/examples/getting_started/pendulum.py
line 117 at r3 (raw file):
# --- Solve the ocp --- # sol = ocp.solve(Solver.IPOPT(show_online_optim=False))
Same here
bioptim/gui/plot.py
line 62 at r3 (raw file):
label: list = None, compute_derivative: bool = False, integration_rule: IntegralApproximation = IntegralApproximation.RECTANGLE,
Should trapezoidal be the default?
bioptim/interfaces/ipopt_interface.py
line 214 at r3 (raw file):
def __get_all_penalties(self, nlp, penalties): def format_target(target_in: list) -> np.array:
Thx for that :)
bioptim/interfaces/ipopt_interface.py
line 294 at r3 (raw file):
target0 = format_target(penalty.target[0:1]) target1 = format_target(penalty.target[1:]) target = np.vstack((target0, target1)).T
This should be
target0 = penalty.target[0]
target1 = penalty.target[1]
Otherwise, what is the point of separating them in a list?
Code quote:
target0 = format_target(penalty.target[0:1])
target1 = format_target(penalty.target[1:])
target = np.vstack((target0, target1)).T
bioptim/limits/objective_functions.py
line 260 at r3 (raw file):
raise ValueError("'list_index' must be defined properly") ocp_or_nlp.J[list_index].target = [new_target]
What if the user already sent the second target (already a list)?
bioptim/limits/penalty.py
line 85 at r3 (raw file):
penalty.quadratic = True if penalty.quadratic is None else penalty.quadratic if penalty.integration_rule == IntegralApproximation.RECTANGLE: penalty.add_target_to_plot(all_pn=all_pn, combine_to=f"{key}_controls")
Please add a todo so we remember some day to implement when it is not rectangle
bioptim/limits/penalty_option.py
line 169 at r3 (raw file):
if len(self.target) == 1 and self.integration_rule == IntegralApproximation.TRAPEZOIDAL: if self.node == Node.ALL or self.node == Node.DEFAULT: self.target = [self.target[0][:, :-1], self.target[0][:, 1:]]
See, you are doing it here already, that should not be done in IPOPT_INTERFACE
bioptim/limits/penalty_option.py
line 173 at r3 (raw file):
raise NotImplementedError( f"target with IntegralApproximation.TRAPEZOIDAL doesn't work with {self.node}, " "it only works if node is Node.NODE_ALL and Node.NODE_DEFAULT"
That is not true, the "automatic" does not work, but one can provide the two columns and it will (should) work. Please rephrase ("Trap needs the beginning and end column values except for NODE_ALL which can be automatically generated" or something like that
Code quote:
raise NotImplementedError(
f"target with IntegralApproximation.TRAPEZOIDAL doesn't work with {self.node}, "
"it only works if node is Node.NODE_ALL and Node.NODE_DEFAULT"
)
bioptim/limits/penalty_option.py
line 179 at r3 (raw file):
self.target_to_plot = None # not implemented yet for trapezoidal integration self.plot_target = False if self.integration_rule == IntegralApproximation.TRAPEZOIDAL else True
Add a todo
bioptim/limits/penalty_option.py
line 298 at r3 (raw file):
elif self.integration_rule == IntegralApproximation.TRAPEZOIDAL: for i in range(2):
for target in self.target
As a rule of thumb, if you find yourself writting "for ... in range(...)" in Python, you are probably doing something wrong
bioptim/limits/penalty_option.py
line 313 at r3 (raw file):
) for i in range(2):
Same. At least len(target).. How do you know it is 2, maybe we implemented polynomial integration?
bioptim/limits/penalty_option.py
line 325 at r3 (raw file):
and all_pn.nlp.ns in all_pn.t and self.target[0].shape[-1] == all_pn.nlp.ns - 1 and self.target[1].shape[-1] == all_pn.nlp.ns - 1
Isn't it always true?
Again, how do you know there are exaclty 2 targets? If someone sends 3 or 4, what happens? I haven't see any control for that yet (maybe later)
Code quote:
and self.target[0].shape[-1] == all_pn.nlp.ns - 1
and self.target[1].shape[-1] == all_pn.nlp.ns - 1
bioptim/limits/penalty_option.py
line 426 at r3 (raw file):
dt_cx = nlp.cx.sym("dt", 1, 1) target_shape = list(sub_fcn.shape)
Why would you save that information?
bioptim/limits/penalty_option.py
line 428 at r3 (raw file):
target_shape = list(sub_fcn.shape) target_shape[1] += 1 if self.integration_rule == IntegralApproximation.TRAPEZOIDAL else 0 target_cx = nlp.cx.sym("target", tuple(target_shape))
why not do
...("target", self.rows, self.cols + 1 if self.integration_rule == IntegralApproximation.TRAPEZOIDAL else 0)
? which replaces the 5 lines before
Code quote:
target_shape[1] += 1 if self.integration_rule == IntegralApproximation.TRAPEZOIDAL else 0
target_cx = nlp.cx.sym("target", tuple(target_shape))
bioptim/limits/penalty_option.py
line 430 at r3 (raw file):
target_cx = nlp.cx.sym("target", tuple(target_shape)) weight_cx = nlp.cx.sym("weight", 1, 1) n = 2 if self.quadratic and self.weight else 1
Please give better naming
bioptim/limits/penalty_option.py
line 467 at r3 (raw file):
self.weighted_function = Function( name, [state_cx, control_cx, param_cx, weight_cx, target_cx, dt_cx], [modified_fcn] ).expand()
please remove this.
expand only if the expand
parameter is to True (see 10 lines later)
bioptim/misc/enums.py
line 136 at r3 (raw file):
""" NONE = None
I am not sure None makes sense...
bioptim/optimization/optimal_control_program.py
line 742 at r3 (raw file):
or penalty.transition ): plot_params["plot_type"] = PlotType.POINT
Just to confirm, this was removed because it shows the wrong result?
Code quote:
isinstance(penalty.type, ObjectiveFcn.Mayer)
or isinstance(penalty.type, ConstraintFcn)
or penalty.transition
):
plot_params["plot_type"] = PlotType.POINT
plot_params["node_idx"] = penalty.node_idx
else:
plot_params["plot_type"] = PlotType.INTEGRATED
Previously, pariterre (Pariterre) wrote…
I didn't understand |
Previously, pariterre (Pariterre) wrote…
IntegralApproximation is fine to me, What about NumericalIntegration ? |
|
Previously, pariterre (Pariterre) wrote…
yes, done. |
Previously, pariterre (Pariterre) wrote…
It has been simplified to ease the readiness of the code. |
Previously, pariterre (Pariterre) wrote…
Done, self.rows is an array of indexes. I needed the size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok done.
Reviewable status: 13 of 14 files reviewed, 21 unresolved discussions (waiting on @pariterre)
bioptim/interfaces/ipopt_interface.py
line 294 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
This should be
target0 = penalty.target[0]
target1 = penalty.target[1]Otherwise, what is the point of separating them in a list?
Done.
bioptim/limits/penalty_option.py
line 169 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
See, you are doing it here already, that should not be done in IPOPT_INTERFACE
I think I resolved that too
bioptim/limits/penalty_option.py
line 325 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
Isn't it always true?
Again, how do you know there are exaclty 2 targets? If someone sends 3 or 4, what happens? I haven't see any control for that yet (maybe later)
Now it is checked.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 10 of 10 files at r6, all commit messages.
Reviewable status: all files reviewed, 7 unresolved discussions (waiting on @Ipuch)
bioptim/__init__.py
line 184 at r3 (raw file):
Previously, Ipuch (Pierre Puchaud) wrote…
IntegralApproximation is fine to me, What about NumericalIntegration ?
Let's leave it as is :)
bioptim/gui/plot.py
line 62 at r3 (raw file):
Previously, Ipuch (Pierre Puchaud) wrote…
If so it will change the value for every single test on an OCP and it will deprecate all the examples designed outside. But yes, let us try it as an option for now and when everybody agreed it is better, let's make the refactor.
To be done later
bioptim/limits/objective_functions.py
line 260 at r3 (raw file):
Previously, Ipuch (Pierre Puchaud) wrote…
Idk. Can you explain more? I've never put my finger into MHE until yesterday.
This comment is not related to MHE, it is related to the user input
bioptim/limits/penalty_option.py
line 298 at r3 (raw file):
Previously, Ipuch (Pierre Puchaud) wrote…
yes, done.
for target in self.target
Code quote:
range(len
bioptim/limits/penalty_option.py
line 426 at r3 (raw file):
Previously, Ipuch (Pierre Puchaud) wrote…
It has been simplified to ease the readiness of the code.
Please use the "is_integrated" I talk later
bioptim/limits/penalty_option.py
line 659 at r6 (raw file):
all_pn.t[:-1] if ( self.integration_rule == IntegralApproximation.TRAPEZOIDAL
You find yourself doing this check over and over and it is confusing.
create a variable:
is_integrated = self.integration_rule == IntegralApproximation.TRAPEZOIDAL or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
and job done
Code quote:
self.integration_rule == IntegralApproximation.TRAPEZOIDAL
or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDAL
tests/test_cost_function_integration.py
line 148 at r6 (raw file):
ocp = prepare_ocp( biorbd_model_path=bioptim_folder + "/models/pendulum.bioMod", n_shooting=30,
that seems a lot... 5? We don't care that the test actually converges... Ideally yes, but not at the expance of a test that is more than 5 to 10 seconds
tests/test_cost_function_integration.py
line 381 at r6 (raw file):
solver = Solver.IPOPT() solver.set_maximum_iterations(1)
I see, that was for to compensate the 30? Maybe 10 iterations so it leaves the beginning enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 7 unresolved discussions (waiting on @pariterre)
bioptim/__init__.py
line 184 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
Let's leave it as is :)
ok
bioptim/gui/plot.py
line 62 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
To be done later
ok
bioptim/limits/objective_functions.py
line 260 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
This comment is not related to MHE, it is related to the user input
modified as,
[new_target] if not isinstance(new_target, list) else new_target
bioptim/limits/penalty_option.py
line 298 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
for target in self.target
Thx, done.
bioptim/limits/penalty_option.py
line 426 at r3 (raw file):
Previously, pariterre (Pariterre) wrote…
Please use the "is_integrated" I talk later
done, with is_trapezoidal
bioptim/limits/penalty_option.py
line 659 at r6 (raw file):
Previously, pariterre (Pariterre) wrote…
You find yourself doing this check over and over and it is confusing.
create a variable:
is_integrated = self.integration_rule == IntegralApproximation.TRAPEZOIDAL or self.integration_rule == IntegralApproximation.TRUE_TRAPEZOIDALand job done
done.
tests/test_cost_function_integration.py
line 148 at r6 (raw file):
Previously, pariterre (Pariterre) wrote…
that seems a lot... 5? We don't care that the test actually converges... Ideally yes, but not at the expance of a test that is more than 5 to 10 seconds
ok.
tests/test_cost_function_integration.py
line 381 at r6 (raw file):
Previously, pariterre (Pariterre) wrote…
I see, that was for to compensate the 30? Maybe 10 iterations so it leaves the beginning enough?
ok. if you want, I picked 5 like the other one.
Codecov Report
@@ Coverage Diff @@
## master #458 +/- ##
==========================================
+ Coverage 80.48% 80.56% +0.07%
==========================================
Files 85 85
Lines 8998 9080 +82
==========================================
+ Hits 7242 7315 +73
- Misses 1756 1765 +9
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 5 of 5 files at r7, all commit messages.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on @Ipuch and @pariterre)
bioptim/limits/objective_functions.py
line 275 at r7 (raw file):
raise ValueError("'list_index' must be defined properly") ocp_or_nlp.J[list_index].target = [new_target] if not isinstance(new_target, list) else new_target
Test for list and tuple
bioptim/limits/penalty_option.py
line 316 at r7 (raw file):
raise RuntimeError(f"targets with trapezoidal integration rule need to get a list of two elements.") for t in self.target:
please call "t" "target"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 13 of 15 files reviewed, 4 unresolved discussions (waiting on @pariterre)
bioptim/limits/objective_functions.py
line 275 at r7 (raw file):
Previously, pariterre (Pariterre) wrote…
Test for list and tuple
done
Code quote:
ocp_or_nlp.J[list_index].target = [new_target] if not isinstance(new_target, list) else new_target
bioptim/limits/penalty_option.py
line 316 at r7 (raw file):
Previously, pariterre (Pariterre) wrote…
please call "t" "target"
done
Code quote:
for t in self.target:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 2 of 2 files at r8, all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on @Ipuch)
All Submissions:
New Feature Submissions:
black . -l120 --exclude "external/*"
)?Changes to Core Features:
related to #416
This change is