I have a question which has already been asked in several other threads, but I need clarification. Similar threads here: https://groups.google.com/forum/#!topic/osqp/VlmMAI2Ti1w
and here:
https://groups.google.com/forum/#!topic/osqp/GhR_71HHzVg
I'm using OSQP in python to solve an MPC problem. If I recreate the OSQP instance and call "setup" at every new timestep, the system is solved (fairly quickly!) correctly. However, if I try to update Ax, q, l, and u (my P matrix stays the same), I get a report of primal infeasibility each time.
I'm using sparse matrices. I set up the initial OSQP instance using a "fully occupied" structure matrix A, with 1's in every location where a nonzero value could potentially be, zeros elsewhere. This matrix has on the order of 400-ish nonzeros. I'm using a csc_matrix from scipy.sparse. I call this structure matrix "A_full", and keep track of the row and column indices like this:
self.A_full = ...
self.A_full.eliminate_zeros()
self.A_full.sort_indices()
(self.A_full_row_indices, self.A_full_col_indices) = self.A_full.nonzero()
self.solver = osqp.OSQP()
self.solver.setup(..., A=self.A_full)
When I construct new A matrices at each new timestep, the sparsity is slightly different (more zeros, in varying places) because of the Jacobians of the changing linearized system. I call this new matrix A_current, and I get an array of values that exactly matches the layout of the A_full matrix by using the indices, like this:
self.A_current = ...
Ax_values = self.A_current[self.A_full_row_indices, self.A_full_col_indices].A1
self.solver.update(..., Ax=Ax_values)
When I do this, I get "primal infeasible" errors. The length of Ax_values is exactly the same as the length of self.A_full.data. I read the matlab example code provided in the threads above by Goran, but it doesn't have the same details of sparse layout as python, so it's impossible to compare.
Given the amount of confusion this seems to cause many many people, it would be incredibly helpful to have an update function that could take a sparse matrix A (and P), and just check that it is a proper sparse subset of the original A and P, and then do the data copying correctly.
What am I doing wrong?
Thanks! Chris
--
You received this message because you are subscribed to a topic in the Google Groups "OSQP" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/osqp/ZFvblAQdUxQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to osqp+uns...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osqp/69bc9611-d7b2-478a-bc55-49dea6a0a78e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hey Paul,Thanks for your quick reply. You outlined the exact steps I'm currently doing, so at least I'm on the right track. If you had an example script of doing this how *you* would do it, that would be immensely helpful. I started off my whole system by evolving the quadcopter MPC control example in your documentation.Meanwhile, I'll see if I can extract a self-contained example.Chris
To unsubscribe from this group and all its topics, send an email to os...@googlegroups.com.
To unsubscribe from this group and all its topics, send an email to osqp+uns...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osqp/ce08720f-b486-4281-ac03-57ab0cbf2245%40googlegroups.com.
B = sparse.csc_matrix([[1, 0, 0, 2], [3, 4, 0, 5], [0, 6, 7, 0], [0, 0, 8, 9]])
print(B.data)
# [1 3 4 6 7 8 2 5 9]
(row_indices, col_indices) = B.nonzero()
print(B[row_indices, col_indices].A1)
# [1 2 3 4 5 6 7 8 9]
Unfortunately you can't get nonzero to sort the indices the other way, so I resorted to this goofy hack.
Bt = B.transpose(copy=True) # Have to copy or it transposes in place
Bt.sort_indices()
# note that col,row are transposed
(col_indices, row_indices) = Bt.nonzero()
print(B[row_indices col_indices].A1)
# [1 3 4 6 7 8 2 5 9]
# Same as B.data!!!
So in my code now, I compute my "full structure matrix" that has 1's anywhere data *could ever be nonzero, and then get the indices from the transposed version of that:
self.A_full = compute_full_structure_matrix()
A_full_transposed = self.A_full.transpose(copy=True)
A_full_transposed.sort_indices()
(self.A_full_col_indices, self.A_full_row_indices) = A_full_transposed.nonzero()
# Then later, I can update from A_current
self.A_current = get_state_matrix_A()
Ax_values = self.A_current[self.A_full_row_indices, self.A_full_col_indices].A1
self.osqp_solver.update(Ax=Ax_values)
I just tried this and it works. It's hard to work this into the existing python API without storing the row and column indices from setup, but that could be done optionally. I could submit a PR with something like that, if there's any interest.
To unsubscribe from this group and all its topics, send an email to osqp+uns...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/osqp/fa833427-01d5-4411-8fcf-32e8a8dad17e%40googlegroups.com.