qdldl_interface.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. #include "glob_opts.h"
  2. #include "qdldl.h"
  3. #include "qdldl_interface.h"
  4. #ifndef EMBEDDED
  5. #include "amd.h"
  6. #endif
  7. #if EMBEDDED != 1
  8. #include "kkt.h"
  9. #endif
  10. #ifndef EMBEDDED
  11. // Free LDL Factorization structure
  12. void free_linsys_solver_qdldl(qdldl_solver *s) {
  13. if (s) {
  14. if (s->L) csc_spfree(s->L);
  15. if (s->P) c_free(s->P);
  16. if (s->Dinv) c_free(s->Dinv);
  17. if (s->bp) c_free(s->bp);
  18. if (s->sol) c_free(s->sol);
  19. if (s->rho_inv_vec) c_free(s->rho_inv_vec);
  20. // These are required for matrix updates
  21. if (s->Pdiag_idx) c_free(s->Pdiag_idx);
  22. if (s->KKT) csc_spfree(s->KKT);
  23. if (s->PtoKKT) c_free(s->PtoKKT);
  24. if (s->AtoKKT) c_free(s->AtoKKT);
  25. if (s->rhotoKKT) c_free(s->rhotoKKT);
  26. // QDLDL workspace
  27. if (s->D) c_free(s->D);
  28. if (s->etree) c_free(s->etree);
  29. if (s->Lnz) c_free(s->Lnz);
  30. if (s->iwork) c_free(s->iwork);
  31. if (s->bwork) c_free(s->bwork);
  32. if (s->fwork) c_free(s->fwork);
  33. c_free(s);
  34. }
  35. }
  36. /**
  37. * Compute LDL factorization of matrix A
  38. * @param A Matrix to be factorized
  39. * @param p Private workspace
  40. * @param nvar Number of QP variables
  41. * @return exitstatus (0 is good)
  42. */
  43. static c_int LDL_factor(csc *A, qdldl_solver * p, c_int nvar){
  44. c_int sum_Lnz;
  45. c_int factor_status;
  46. // Compute elimination tree
  47. sum_Lnz = QDLDL_etree(A->n, A->p, A->i, p->iwork, p->Lnz, p->etree);
  48. if (sum_Lnz < 0){
  49. // Error
  50. #ifdef PRINTING
  51. c_eprint("Error in KKT matrix LDL factorization when computing the elimination tree. A is not perfectly upper triangular");
  52. #endif
  53. return sum_Lnz;
  54. }
  55. // Allocate memory for Li and Lx
  56. p->L->i = (c_int *)c_malloc(sizeof(c_int)*sum_Lnz);
  57. p->L->x = (c_float *)c_malloc(sizeof(c_float)*sum_Lnz);
  58. // Factor matrix
  59. factor_status = QDLDL_factor(A->n, A->p, A->i, A->x,
  60. p->L->p, p->L->i, p->L->x,
  61. p->D, p->Dinv, p->Lnz,
  62. p->etree, p->bwork, p->iwork, p->fwork);
  63. if (factor_status < 0){
  64. // Error
  65. #ifdef PRINTING
  66. c_eprint("Error in KKT matrix LDL factorization when computing the nonzero elements. There are zeros in the diagonal matrix");
  67. #endif
  68. return factor_status;
  69. } else if (factor_status < nvar) {
  70. // Error: Number of positive elements of D should be equal to nvar
  71. #ifdef PRINTING
  72. c_eprint("Error in KKT matrix LDL factorization when computing the nonzero elements. The problem seems to be non-convex");
  73. #endif
  74. return -2;
  75. }
  76. return 0;
  77. }
  78. static c_int permute_KKT(csc ** KKT, qdldl_solver * p, c_int Pnz, c_int Anz, c_int m, c_int * PtoKKT, c_int * AtoKKT, c_int * rhotoKKT){
  79. c_float *info;
  80. c_int amd_status;
  81. c_int * Pinv;
  82. csc *KKT_temp;
  83. c_int * KtoPKPt;
  84. c_int i; // Indexing
  85. info = (c_float *)c_malloc(AMD_INFO * sizeof(c_float));
  86. // Compute permutation matrix P using AMD
  87. #ifdef DLONG
  88. amd_status = amd_l_order((*KKT)->n, (*KKT)->p, (*KKT)->i, p->P, (c_float *)OSQP_NULL, info);
  89. #else
  90. amd_status = amd_order((*KKT)->n, (*KKT)->p, (*KKT)->i, p->P, (c_float *)OSQP_NULL, info);
  91. #endif
  92. if (amd_status < 0) {
  93. // Free Amd info and return an error
  94. c_free(info);
  95. return amd_status;
  96. }
  97. // Inverse of the permutation vector
  98. Pinv = csc_pinv(p->P, (*KKT)->n);
  99. // Permute KKT matrix
  100. if (!PtoKKT && !AtoKKT && !rhotoKKT){ // No vectors to be stored
  101. // Assign values of mapping
  102. KKT_temp = csc_symperm((*KKT), Pinv, OSQP_NULL, 1);
  103. }
  104. else {
  105. // Allocate vector of mappings from unpermuted to permuted
  106. KtoPKPt = c_malloc((*KKT)->p[(*KKT)->n] * sizeof(c_int));
  107. KKT_temp = csc_symperm((*KKT), Pinv, KtoPKPt, 1);
  108. // Update vectors PtoKKT, AtoKKT and rhotoKKT
  109. if (PtoKKT){
  110. for (i = 0; i < Pnz; i++){
  111. PtoKKT[i] = KtoPKPt[PtoKKT[i]];
  112. }
  113. }
  114. if (AtoKKT){
  115. for (i = 0; i < Anz; i++){
  116. AtoKKT[i] = KtoPKPt[AtoKKT[i]];
  117. }
  118. }
  119. if (rhotoKKT){
  120. for (i = 0; i < m; i++){
  121. rhotoKKT[i] = KtoPKPt[rhotoKKT[i]];
  122. }
  123. }
  124. // Cleanup vector of mapping
  125. c_free(KtoPKPt);
  126. }
  127. // Cleanup
  128. // Free previous KKT matrix and assign pointer to new one
  129. csc_spfree((*KKT));
  130. (*KKT) = KKT_temp;
  131. // Free Pinv
  132. c_free(Pinv);
  133. // Free Amd info
  134. c_free(info);
  135. return 0;
  136. }
  137. // Initialize LDL Factorization structure
  138. c_int init_linsys_solver_qdldl(qdldl_solver ** sp, const csc * P, const csc * A, c_float sigma, const c_float * rho_vec, c_int polish){
  139. // Define Variables
  140. csc * KKT_temp; // Temporary KKT pointer
  141. c_int i; // Loop counter
  142. c_int n_plus_m; // Define n_plus_m dimension
  143. // Allocate private structure to store KKT factorization
  144. qdldl_solver *s;
  145. s = c_calloc(1, sizeof(qdldl_solver));
  146. *sp = s;
  147. // Size of KKT
  148. s->n = P->n;
  149. s->m = A->m;
  150. n_plus_m = s->n + s->m;
  151. // Sigma parameter
  152. s->sigma = sigma;
  153. // Polishing flag
  154. s->polish = polish;
  155. // Link Functions
  156. s->solve = &solve_linsys_qdldl;
  157. #ifndef EMBEDDED
  158. s->free = &free_linsys_solver_qdldl;
  159. #endif
  160. #if EMBEDDED != 1
  161. s->update_matrices = &update_linsys_solver_matrices_qdldl;
  162. s->update_rho_vec = &update_linsys_solver_rho_vec_qdldl;
  163. #endif
  164. // Assign type
  165. s->type = QDLDL_SOLVER;
  166. // Set number of threads to 1 (single threaded)
  167. s->nthreads = 1;
  168. // Sparse matrix L (lower triangular)
  169. // NB: We don not allocate L completely (CSC elements)
  170. // L will be allocated during the factorization depending on the
  171. // resulting number of elements.
  172. s->L = c_malloc(sizeof(csc));
  173. s->L->m = n_plus_m;
  174. s->L->n = n_plus_m;
  175. s->L->nz = -1;
  176. // Diagonal matrix stored as a vector D
  177. s->Dinv = (QDLDL_float *)c_malloc(sizeof(QDLDL_float) * n_plus_m);
  178. s->D = (QDLDL_float *)c_malloc(sizeof(QDLDL_float) * n_plus_m);
  179. // Permutation vector P
  180. s->P = (QDLDL_int *)c_malloc(sizeof(QDLDL_int) * n_plus_m);
  181. // Working vector
  182. s->bp = (QDLDL_float *)c_malloc(sizeof(QDLDL_float) * n_plus_m);
  183. // Solution vector
  184. s->sol = (QDLDL_float *)c_malloc(sizeof(QDLDL_float) * n_plus_m);
  185. // Parameter vector
  186. s->rho_inv_vec = (c_float *)c_malloc(sizeof(c_float) * s->m);
  187. // Elimination tree workspace
  188. s->etree = (QDLDL_int *)c_malloc(n_plus_m * sizeof(QDLDL_int));
  189. s->Lnz = (QDLDL_int *)c_malloc(n_plus_m * sizeof(QDLDL_int));
  190. // Preallocate L matrix (Lx and Li are sparsity dependent)
  191. s->L->p = (c_int *)c_malloc((n_plus_m+1) * sizeof(QDLDL_int));
  192. // Lx and Li are sparsity dependent, so set them to
  193. // null initially so we don't try to free them prematurely
  194. s->L->i = OSQP_NULL;
  195. s->L->x = OSQP_NULL;
  196. // Preallocate workspace
  197. s->iwork = (QDLDL_int *)c_malloc(sizeof(QDLDL_int)*(3*n_plus_m));
  198. s->bwork = (QDLDL_bool *)c_malloc(sizeof(QDLDL_bool)*n_plus_m);
  199. s->fwork = (QDLDL_float *)c_malloc(sizeof(QDLDL_float)*n_plus_m);
  200. // Form and permute KKT matrix
  201. if (polish){ // Called from polish()
  202. // Use s->rho_inv_vec for storing param2 = vec(delta)
  203. for (i = 0; i < A->m; i++){
  204. s->rho_inv_vec[i] = sigma;
  205. }
  206. KKT_temp = form_KKT(P, A, 0, sigma, s->rho_inv_vec, OSQP_NULL, OSQP_NULL, OSQP_NULL, OSQP_NULL, OSQP_NULL);
  207. // Permute matrix
  208. if (KKT_temp)
  209. permute_KKT(&KKT_temp, s, OSQP_NULL, OSQP_NULL, OSQP_NULL, OSQP_NULL, OSQP_NULL, OSQP_NULL);
  210. }
  211. else { // Called from ADMM algorithm
  212. // Allocate vectors of indices
  213. s->PtoKKT = c_malloc((P->p[P->n]) * sizeof(c_int));
  214. s->AtoKKT = c_malloc((A->p[A->n]) * sizeof(c_int));
  215. s->rhotoKKT = c_malloc((A->m) * sizeof(c_int));
  216. // Use p->rho_inv_vec for storing param2 = rho_inv_vec
  217. for (i = 0; i < A->m; i++){
  218. s->rho_inv_vec[i] = 1. / rho_vec[i];
  219. }
  220. KKT_temp = form_KKT(P, A, 0, sigma, s->rho_inv_vec,
  221. s->PtoKKT, s->AtoKKT,
  222. &(s->Pdiag_idx), &(s->Pdiag_n), s->rhotoKKT);
  223. // Permute matrix
  224. if (KKT_temp)
  225. permute_KKT(&KKT_temp, s, P->p[P->n], A->p[A->n], A->m, s->PtoKKT, s->AtoKKT, s->rhotoKKT);
  226. }
  227. // Check if matrix has been created
  228. if (!KKT_temp){
  229. #ifdef PRINTING
  230. c_eprint("Error forming and permuting KKT matrix");
  231. #endif
  232. free_linsys_solver_qdldl(s);
  233. *sp = OSQP_NULL;
  234. return OSQP_LINSYS_SOLVER_INIT_ERROR;
  235. }
  236. // Factorize the KKT matrix
  237. if (LDL_factor(KKT_temp, s, P->n) < 0) {
  238. csc_spfree(KKT_temp);
  239. free_linsys_solver_qdldl(s);
  240. *sp = OSQP_NULL;
  241. return OSQP_NONCVX_ERROR;
  242. }
  243. if (polish){ // If KKT passed, assign it to KKT_temp
  244. // Polish, no need for KKT_temp
  245. csc_spfree(KKT_temp);
  246. }
  247. else { // If not embedded option 1 copy pointer to KKT_temp. Do not free it.
  248. s->KKT = KKT_temp;
  249. }
  250. // No error
  251. return 0;
  252. }
  253. #endif // EMBEDDED
  254. // Permute x = P*b using P
  255. void permute_x(c_int n, c_float * x, const c_float * b, const c_int * P) {
  256. c_int j;
  257. for (j = 0 ; j < n ; j++) x[j] = b[P[j]];
  258. }
  259. // Permute x = P'*b using P
  260. void permutet_x(c_int n, c_float * x, const c_float * b, const c_int * P) {
  261. c_int j;
  262. for (j = 0 ; j < n ; j++) x[P[j]] = b[j];
  263. }
  264. static void LDLSolve(c_float *x, c_float *b, const csc *L, const c_float *Dinv, const c_int *P, c_float *bp) {
  265. /* solves P'LDL'P x = b for x */
  266. permute_x(L->n, bp, b, P);
  267. QDLDL_solve(L->n, L->p, L->i, L->x, Dinv, bp);
  268. permutet_x(L->n, x, bp, P);
  269. }
  270. c_int solve_linsys_qdldl(qdldl_solver * s, c_float * b) {
  271. c_int j;
  272. #ifndef EMBEDDED
  273. if (s->polish) {
  274. /* stores solution to the KKT system in b */
  275. LDLSolve(b, b, s->L, s->Dinv, s->P, s->bp);
  276. } else {
  277. #endif
  278. /* stores solution to the KKT system in s->sol */
  279. LDLSolve(s->sol, b, s->L, s->Dinv, s->P, s->bp);
  280. /* copy x_tilde from s->sol */
  281. for (j = 0 ; j < s->n ; j++) {
  282. b[j] = s->sol[j];
  283. }
  284. /* compute z_tilde from b and s->sol */
  285. for (j = 0 ; j < s->m ; j++) {
  286. b[j + s->n] += s->rho_inv_vec[j] * s->sol[j + s->n];
  287. }
  288. #ifndef EMBEDDED
  289. }
  290. #endif
  291. return 0;
  292. }
  293. #if EMBEDDED != 1
  294. // Update private structure with new P and A
  295. c_int update_linsys_solver_matrices_qdldl(qdldl_solver * s, const csc *P, const csc *A) {
  296. // Update KKT matrix with new P
  297. update_KKT_P(s->KKT, P, s->PtoKKT, s->sigma, s->Pdiag_idx, s->Pdiag_n);
  298. // Update KKT matrix with new A
  299. update_KKT_A(s->KKT, A, s->AtoKKT);
  300. return (QDLDL_factor(s->KKT->n, s->KKT->p, s->KKT->i, s->KKT->x,
  301. s->L->p, s->L->i, s->L->x, s->D, s->Dinv, s->Lnz,
  302. s->etree, s->bwork, s->iwork, s->fwork) < 0);
  303. }
  304. c_int update_linsys_solver_rho_vec_qdldl(qdldl_solver * s, const c_float * rho_vec){
  305. c_int i;
  306. // Update internal rho_inv_vec
  307. for (i = 0; i < s->m; i++){
  308. s->rho_inv_vec[i] = 1. / rho_vec[i];
  309. }
  310. // Update KKT matrix with new rho_vec
  311. update_KKT_param2(s->KKT, s->rho_inv_vec, s->rhotoKKT, s->m);
  312. return (QDLDL_factor(s->KKT->n, s->KKT->p, s->KKT->i, s->KKT->x,
  313. s->L->p, s->L->i, s->L->x, s->D, s->Dinv, s->Lnz,
  314. s->etree, s->bwork, s->iwork, s->fwork) < 0);
  315. }
  316. #endif