Closed Peter230655 closed 3 months ago
Yeah, I actually guess that this is a bug. The plot constraint function should never crash after successfully solving a problem. I also remember having the same problem and writing my own version of this function.
Just gave the source code a quick read. The problem is in the slicing of the selecting the values of the instance constraints of the free vector. It uses con_violations[self.collocator.num_states * N:]
and forgets the unknown input trajectories.
Thanks!
Just gave the source code a quick read. The problem is in the slicing of the selecting the values of the instance constraints of the free vector. It uses
con_violations[self.collocator.num_states * N:]
and forgets the unknown input trajectories.
Oh wait, this statement is incorrect, we are dealing here with the constraints vector, not the free
vector. I'll have to check how this array is actually formatted.
There is this probably related issue #53 .
There is this probably related issue #53 .
I think it is not exactly related (unless it really has to do with the initial slicing), but it can be easily fixed at the same time. I would propose something like the following, where I immediately also introduce the option to just plot all state violations in a single axis, as that is way more readable when having more states.
def plot_constraint_violations(self, vector, separate_state_axes=True):
con_violations = self.con(vector)
con_nodes = range(self.collocator.num_states, # Have to say that I do not exactly know where this part comes from
self.collocator.num_collocation_nodes + 1)
N = len(con_nodes)
n_state_axes = len(self.collocator.state_symbols) if separate_state_axes else 1
plot_instance_viols = self.coll_instance_constraints is not None
fig, axes = plt.subplots(n_state_axes + plot_instance_viols)
for i, symbol in enumerate(self.collocator.state_symbols):
state_violations = con_violations[i * N:i * N + N]
state_label = sm.latex(symbol, mode='inline')
if separate_state_axes:
axes[i].plot(con_nodes, state_violations)
axes[i].set_ylabel(state_label)
else:
axes[0].plot(con_nodes, state_violations, label=state_label)
if not separate_state_axes:
axes[0].legend()
axes[0].set_title('Constraint Violations')
axes[-plot_instance_viols - 1].set_xlabel('Node Number')
if plot_instance_viols:
left = range(len(self.collocator.instance_constraints))
axes[-1].bar(left, con_violations[-len(self.collocator.instance_constraints):],
tick_label=[sm.latex(s, mode='inline')
for s in self.collocator.instance_constraints])
axes[-1].set_ylabel('Instance')
axes[-1].set_xticklabels(axes[-1].get_xticklabels(), rotation=-10)
return axes
PS a more future proof argument could be state_style="separate axes"
Any improvement to the plots are welcome. I didn't spend too much time making them nice years ago when I drafted this.
Dumb question: Does this line: _prob.plot_constraint_violations(solution)__ plot the content of info[g], where info is the dictionary returned by solve? Thanks!
I am playing around with a opty simulation.
The last line (prob.plot_constraint_violations(solution)) gives this error:
However it does print some result:![Screenshot 2024-02-13 210319](https://github.com/csu-hmc/opty/assets/83544146/eeee7216-134a-4b81-8c11-06b71611c079)
What am I doing wrong? Thanks for any help!