blob: 94819b35f9d7cd31cec8d0d136648c60daded093 [file] [log] [blame]
Austin Schuh9049e202022-02-20 17:34:16 -08001#include "osqp.h"
2#include "auxil.h"
3#include "util.h"
4#include "scaling.h"
5#include "glob_opts.h"
Austin Schuhd9e9dea2022-02-20 19:54:42 -08006#include "osqp_error.h"
Austin Schuh9049e202022-02-20 17:34:16 -08007
8
9#ifndef EMBEDDED
10# include "polish.h"
11#endif /* ifndef EMBEDDED */
12
13#ifdef CTRLC
14# include "ctrlc.h"
15#endif /* ifdef CTRLC */
16
17#ifndef EMBEDDED
18# include "lin_sys.h"
19#endif /* ifndef EMBEDDED */
20
21/**********************
22* Main API Functions *
23**********************/
24void osqp_set_default_settings(OSQPSettings *settings) {
25
26 settings->rho = (c_float)RHO; /* ADMM step */
27 settings->sigma = (c_float)SIGMA; /* ADMM step */
28 settings->scaling = SCALING; /* heuristic problem scaling */
29#if EMBEDDED != 1
30 settings->adaptive_rho = ADAPTIVE_RHO;
31 settings->adaptive_rho_interval = ADAPTIVE_RHO_INTERVAL;
32 settings->adaptive_rho_tolerance = (c_float)ADAPTIVE_RHO_TOLERANCE;
33
34# ifdef PROFILING
35 settings->adaptive_rho_fraction = (c_float)ADAPTIVE_RHO_FRACTION;
36# endif /* ifdef PROFILING */
37#endif /* if EMBEDDED != 1 */
38
39 settings->max_iter = MAX_ITER; /* maximum iterations to
40 take */
41 settings->eps_abs = (c_float)EPS_ABS; /* absolute convergence
42 tolerance */
43 settings->eps_rel = (c_float)EPS_REL; /* relative convergence
44 tolerance */
45 settings->eps_prim_inf = (c_float)EPS_PRIM_INF; /* primal infeasibility
46 tolerance */
47 settings->eps_dual_inf = (c_float)EPS_DUAL_INF; /* dual infeasibility
48 tolerance */
49 settings->alpha = (c_float)ALPHA; /* relaxation parameter */
50 settings->linsys_solver = LINSYS_SOLVER; /* relaxation parameter */
51
52#ifndef EMBEDDED
53 settings->delta = DELTA; /* regularization parameter
54 for polish */
55 settings->polish = POLISH; /* ADMM solution polish: 1
56 */
57 settings->polish_refine_iter = POLISH_REFINE_ITER; /* iterative refinement
58 steps in polish */
59 settings->verbose = VERBOSE; /* print output */
60#endif /* ifndef EMBEDDED */
61
62 settings->scaled_termination = SCALED_TERMINATION; /* Evaluate scaled
63 termination criteria*/
64 settings->check_termination = CHECK_TERMINATION; /* Interval for evaluating
65 termination criteria */
66 settings->warm_start = WARM_START; /* warm starting */
67
68#ifdef PROFILING
69 settings->time_limit = TIME_LIMIT;
70#endif /* ifdef PROFILING */
71}
72
73#ifndef EMBEDDED
74
75
76c_int osqp_setup(OSQPWorkspace** workp, const OSQPData *data, const OSQPSettings *settings) {
77 c_int exitflag;
78
79 OSQPWorkspace * work;
80
81 // Validate data
82 if (validate_data(data)) return osqp_error(OSQP_DATA_VALIDATION_ERROR);
83
84 // Validate settings
85 if (validate_settings(settings)) return osqp_error(OSQP_SETTINGS_VALIDATION_ERROR);
86
87 // Allocate empty workspace
88 work = c_calloc(1, sizeof(OSQPWorkspace));
89 if (!(work)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
90 *workp = work;
91
92 // Start and allocate directly timer
93# ifdef PROFILING
94 work->timer = c_malloc(sizeof(OSQPTimer));
95 if (!(work->timer)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
96 osqp_tic(work->timer);
97# endif /* ifdef PROFILING */
98
99 // Copy problem data into workspace
100 work->data = c_malloc(sizeof(OSQPData));
101 if (!(work->data)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
102 work->data->n = data->n;
103 work->data->m = data->m;
104
105 // Cost function
106 work->data->P = copy_csc_mat(data->P);
107 work->data->q = vec_copy(data->q, data->n);
108 if (!(work->data->P) || !(work->data->q)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
109
110 // Constraints
111 work->data->A = copy_csc_mat(data->A);
112 if (!(work->data->A)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
113 work->data->l = vec_copy(data->l, data->m);
114 work->data->u = vec_copy(data->u, data->m);
115 if ( data->m && (!(work->data->l) || !(work->data->u)) )
116 return osqp_error(OSQP_MEM_ALLOC_ERROR);
117
118 // Vectorized rho parameter
119 work->rho_vec = c_malloc(data->m * sizeof(c_float));
120 work->rho_inv_vec = c_malloc(data->m * sizeof(c_float));
121 if ( data->m && (!(work->rho_vec) || !(work->rho_inv_vec)) )
122 return osqp_error(OSQP_MEM_ALLOC_ERROR);
123
124 // Type of constraints
125 work->constr_type = c_calloc(data->m, sizeof(c_int));
126 if (data->m && !(work->constr_type)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
127
128 // Allocate internal solver variables (ADMM steps)
129 work->x = c_calloc(data->n, sizeof(c_float));
130 work->z = c_calloc(data->m, sizeof(c_float));
131 work->xz_tilde = c_calloc(data->n + data->m, sizeof(c_float));
132 work->x_prev = c_calloc(data->n, sizeof(c_float));
133 work->z_prev = c_calloc(data->m, sizeof(c_float));
134 work->y = c_calloc(data->m, sizeof(c_float));
135 if (!(work->x) || !(work->xz_tilde) || !(work->x_prev))
136 return osqp_error(OSQP_MEM_ALLOC_ERROR);
137 if ( data->m && (!(work->z) || !(work->z_prev) || !(work->y)) )
138 return osqp_error(OSQP_MEM_ALLOC_ERROR);
139
140 // Initialize variables x, y, z to 0
141 cold_start(work);
142
143 // Primal and dual residuals variables
144 work->Ax = c_calloc(data->m, sizeof(c_float));
145 work->Px = c_calloc(data->n, sizeof(c_float));
146 work->Aty = c_calloc(data->n, sizeof(c_float));
147
148 // Primal infeasibility variables
149 work->delta_y = c_calloc(data->m, sizeof(c_float));
150 work->Atdelta_y = c_calloc(data->n, sizeof(c_float));
151
152 // Dual infeasibility variables
153 work->delta_x = c_calloc(data->n, sizeof(c_float));
154 work->Pdelta_x = c_calloc(data->n, sizeof(c_float));
155 work->Adelta_x = c_calloc(data->m, sizeof(c_float));
156
157 if (!(work->Px) || !(work->Aty) || !(work->Atdelta_y) ||
158 !(work->delta_x) || !(work->Pdelta_x))
159 return osqp_error(OSQP_MEM_ALLOC_ERROR);
160 if ( data->m && (!(work->Ax) || !(work->delta_y) || !(work->Adelta_x)) )
161 return osqp_error(OSQP_MEM_ALLOC_ERROR);
162
163 // Copy settings
164 work->settings = copy_settings(settings);
165 if (!(work->settings)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
166
167 // Perform scaling
168 if (settings->scaling) {
169 // Allocate scaling structure
170 work->scaling = c_malloc(sizeof(OSQPScaling));
171 if (!(work->scaling)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
172 work->scaling->D = c_malloc(data->n * sizeof(c_float));
173 work->scaling->Dinv = c_malloc(data->n * sizeof(c_float));
174 work->scaling->E = c_malloc(data->m * sizeof(c_float));
175 work->scaling->Einv = c_malloc(data->m * sizeof(c_float));
176 if (!(work->scaling->D) || !(work->scaling->Dinv))
177 return osqp_error(OSQP_MEM_ALLOC_ERROR);
178 if ( data->m && (!(work->scaling->E) || !(work->scaling->Einv)) )
179 return osqp_error(OSQP_MEM_ALLOC_ERROR);
180
181
182 // Allocate workspace variables used in scaling
183 work->D_temp = c_malloc(data->n * sizeof(c_float));
184 work->D_temp_A = c_malloc(data->n * sizeof(c_float));
185 work->E_temp = c_malloc(data->m * sizeof(c_float));
186 // if (!(work->D_temp) || !(work->D_temp_A) || !(work->E_temp))
187 // return osqp_error(OSQP_MEM_ALLOC_ERROR);
188 if (!(work->D_temp) || !(work->D_temp_A)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
189 if (data->m && !(work->E_temp)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
190
191 // Scale data
192 scale_data(work);
193 } else {
194 work->scaling = OSQP_NULL;
195 work->D_temp = OSQP_NULL;
196 work->D_temp_A = OSQP_NULL;
197 work->E_temp = OSQP_NULL;
198 }
199
200 // Set type of constraints
201 set_rho_vec(work);
202
203 // Load linear system solver
204 if (load_linsys_solver(work->settings->linsys_solver)) return osqp_error(OSQP_LINSYS_SOLVER_LOAD_ERROR);
205
206 // Initialize linear system solver structure
207 exitflag = init_linsys_solver(&(work->linsys_solver), work->data->P, work->data->A,
208 work->settings->sigma, work->rho_vec,
209 work->settings->linsys_solver, 0);
210
211 if (exitflag) {
212 return osqp_error(exitflag);
213 }
214
215 // Initialize active constraints structure
216 work->pol = c_malloc(sizeof(OSQPPolish));
217 if (!(work->pol)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
218 work->pol->Alow_to_A = c_malloc(data->m * sizeof(c_int));
219 work->pol->Aupp_to_A = c_malloc(data->m * sizeof(c_int));
220 work->pol->A_to_Alow = c_malloc(data->m * sizeof(c_int));
221 work->pol->A_to_Aupp = c_malloc(data->m * sizeof(c_int));
222 work->pol->x = c_malloc(data->n * sizeof(c_float));
223 work->pol->z = c_malloc(data->m * sizeof(c_float));
224 work->pol->y = c_malloc(data->m * sizeof(c_float));
225 if (!(work->pol->x)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
226 if ( data->m && (!(work->pol->Alow_to_A) || !(work->pol->Aupp_to_A) ||
227 !(work->pol->A_to_Alow) || !(work->pol->A_to_Aupp) ||
228 !(work->pol->z) || !(work->pol->y)) )
229 return osqp_error(OSQP_MEM_ALLOC_ERROR);
230
231 // Allocate solution
232 work->solution = c_calloc(1, sizeof(OSQPSolution));
233 if (!(work->solution)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
234 work->solution->x = c_calloc(1, data->n * sizeof(c_float));
235 work->solution->y = c_calloc(1, data->m * sizeof(c_float));
236 if (!(work->solution->x)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
237 if (data->m && !(work->solution->y)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
238
239 // Allocate and initialize information
240 work->info = c_calloc(1, sizeof(OSQPInfo));
241 if (!(work->info)) return osqp_error(OSQP_MEM_ALLOC_ERROR);
242 work->info->status_polish = 0; // Polishing not performed
243 update_status(work->info, OSQP_UNSOLVED);
244# ifdef PROFILING
245 work->info->solve_time = 0.0; // Solve time to zero
246 work->info->update_time = 0.0; // Update time to zero
247 work->info->polish_time = 0.0; // Polish time to zero
248 work->info->run_time = 0.0; // Total run time to zero
249 work->info->setup_time = osqp_toc(work->timer); // Update timer information
250
251 work->first_run = 1;
252 work->clear_update_time = 0;
253 work->rho_update_from_solve = 0;
254# endif /* ifdef PROFILING */
255 work->info->rho_updates = 0; // Rho updates set to 0
256 work->info->rho_estimate = work->settings->rho; // Best rho estimate
257
258 // Print header
259# ifdef PRINTING
260 if (work->settings->verbose) print_setup_header(work);
261 work->summary_printed = 0; // Initialize last summary to not printed
262# endif /* ifdef PRINTING */
263
264
265 // If adaptive rho and automatic interval, but profiling disabled, we need to
266 // set the interval to a default value
267# ifndef PROFILING
268 if (work->settings->adaptive_rho && !work->settings->adaptive_rho_interval) {
269 if (work->settings->check_termination) {
270 // If check_termination is enabled, we set it to a multiple of the check
271 // termination interval
272 work->settings->adaptive_rho_interval = ADAPTIVE_RHO_MULTIPLE_TERMINATION *
273 work->settings->check_termination;
274 } else {
275 // If check_termination is disabled we set it to a predefined fix number
276 work->settings->adaptive_rho_interval = ADAPTIVE_RHO_FIXED;
277 }
278 }
279# endif /* ifndef PROFILING */
280
281 // Return exit flag
282 return 0;
283}
284
285#endif // #ifndef EMBEDDED
286
287
288c_int osqp_solve(OSQPWorkspace *work) {
289
290 c_int exitflag;
291 c_int iter;
292 c_int compute_cost_function; // Boolean: compute the cost function in the loop or not
293 c_int can_check_termination; // Boolean: check termination or not
294
295#ifdef PROFILING
296 c_float temp_run_time; // Temporary variable to store current run time
297#endif /* ifdef PROFILING */
298
299#ifdef PRINTING
300 c_int can_print; // Boolean whether you can print
301#endif /* ifdef PRINTING */
302
303 // Check if workspace has been initialized
304 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
305
306#ifdef PROFILING
307 if (work->clear_update_time == 1)
308 work->info->update_time = 0.0;
309 work->rho_update_from_solve = 1;
310#endif /* ifdef PROFILING */
311
312 // Initialize variables
313 exitflag = 0;
314 can_check_termination = 0;
315#ifdef PRINTING
316 can_print = work->settings->verbose;
317#endif /* ifdef PRINTING */
318#ifdef PRINTING
319 compute_cost_function = work->settings->verbose; // Compute cost function only
320 // if verbose is on
321#else /* ifdef PRINTING */
322 compute_cost_function = 0; // Never compute cost
323 // function during the
324 // iterations if no printing
325 // enabled
326#endif /* ifdef PRINTING */
327
328
329
330#ifdef PROFILING
331 osqp_tic(work->timer); // Start timer
332#endif /* ifdef PROFILING */
333
334
335#ifdef PRINTING
336
337 if (work->settings->verbose) {
338 // Print Header for every column
339 print_header();
340 }
341#endif /* ifdef PRINTING */
342
343#ifdef CTRLC
344
345 // initialize Ctrl-C support
346 osqp_start_interrupt_listener();
347#endif /* ifdef CTRLC */
348
349 // Initialize variables (cold start or warm start depending on settings)
350 if (!work->settings->warm_start) cold_start(work); // If not warm start ->
351 // set x, z, y to zero
352
353 // Main ADMM algorithm
354 for (iter = 1; iter <= work->settings->max_iter; iter++) {
355 // Update x_prev, z_prev (preallocated, no malloc)
356 swap_vectors(&(work->x), &(work->x_prev));
357 swap_vectors(&(work->z), &(work->z_prev));
358
359 /* ADMM STEPS */
360 /* Compute \tilde{x}^{k+1}, \tilde{z}^{k+1} */
361 update_xz_tilde(work);
362
363 /* Compute x^{k+1} */
364 update_x(work);
365
366 /* Compute z^{k+1} */
367 update_z(work);
368
369 /* Compute y^{k+1} */
370 update_y(work);
371
372 /* End of ADMM Steps */
373
374#ifdef CTRLC
375
376 // Check the interrupt signal
377 if (osqp_is_interrupted()) {
378 update_status(work->info, OSQP_SIGINT);
379# ifdef PRINTING
380 c_print("Solver interrupted\n");
381# endif /* ifdef PRINTING */
382 exitflag = 1;
383 goto exit;
384 }
385#endif /* ifdef CTRLC */
386
387#ifdef PROFILING
388
389 // Check if solver time_limit is enabled. In case, check if the current
390 // run time is more than the time_limit option.
391 if (work->first_run) {
392 temp_run_time = work->info->setup_time + osqp_toc(work->timer);
393 }
394 else {
395 temp_run_time = work->info->update_time + osqp_toc(work->timer);
396 }
397
398 if (work->settings->time_limit &&
399 (temp_run_time >= work->settings->time_limit)) {
400 update_status(work->info, OSQP_TIME_LIMIT_REACHED);
401# ifdef PRINTING
402 if (work->settings->verbose) c_print("run time limit reached\n");
403 can_print = 0; // Not printing at this iteration
404# endif /* ifdef PRINTING */
405 break;
406 }
407#endif /* ifdef PROFILING */
408
409
410 // Can we check for termination ?
411 can_check_termination = work->settings->check_termination &&
412 (iter % work->settings->check_termination == 0);
413
414#ifdef PRINTING
415
416 // Can we print ?
417 can_print = work->settings->verbose &&
418 ((iter % PRINT_INTERVAL == 0) || (iter == 1));
419
420 if (can_check_termination || can_print) { // Update status in either of
421 // these cases
422 // Update information
423 update_info(work, iter, compute_cost_function, 0);
424
425 if (can_print) {
426 // Print summary
427 print_summary(work);
428 }
429
430 if (can_check_termination) {
431 // Check algorithm termination
432 if (check_termination(work, 0)) {
433 // Terminate algorithm
434 break;
435 }
436 }
437 }
438#else /* ifdef PRINTING */
439
440 if (can_check_termination) {
441 // Update information and compute also objective value
442 update_info(work, iter, compute_cost_function, 0);
443
444 // Check algorithm termination
445 if (check_termination(work, 0)) {
446 // Terminate algorithm
447 break;
448 }
449 }
450#endif /* ifdef PRINTING */
451
452
453#if EMBEDDED != 1
454# ifdef PROFILING
455
456 // If adaptive rho with automatic interval, check if the solve time is a
457 // certain fraction
458 // of the setup time.
459 if (work->settings->adaptive_rho && !work->settings->adaptive_rho_interval) {
460 // Check time
461 if (osqp_toc(work->timer) >
462 work->settings->adaptive_rho_fraction * work->info->setup_time) {
463 // Enough time has passed. We now get the number of iterations between
464 // the updates.
465 if (work->settings->check_termination) {
466 // If check_termination is enabled, we round the number of iterations
467 // between
468 // rho updates to the closest multiple of check_termination
469 work->settings->adaptive_rho_interval = (c_int)c_roundmultiple(iter,
470 work->settings->check_termination);
471 } else {
472 // If check_termination is disabled, we round the number of iterations
473 // between
474 // updates to the closest multiple of the default check_termination
475 // interval.
476 work->settings->adaptive_rho_interval = (c_int)c_roundmultiple(iter,
477 CHECK_TERMINATION);
478 }
479
480 // Make sure the interval is not 0 and at least check_termination times
481 work->settings->adaptive_rho_interval = c_max(
482 work->settings->adaptive_rho_interval,
483 work->settings->check_termination);
484 } // If time condition is met
485 } // If adaptive rho enabled and interval set to auto
486# else // PROFILING
487 if (work->settings->adaptive_rho && !work->settings->adaptive_rho_interval) {
488 // Set adaptive_rho_interval to constant value
489 if (work->settings->check_termination) {
490 // If check_termination is enabled, we set it to a multiple of the check
491 // termination interval
492 work->settings->adaptive_rho_interval = ADAPTIVE_RHO_MULTIPLE_TERMINATION *
493 work->settings->check_termination;
494 } else {
495 // If check_termination is disabled we set it to a predefined fix number
496 work->settings->adaptive_rho_interval = ADAPTIVE_RHO_FIXED;
497 }
498 }
499# endif /* ifdef PROFILING */
500
501 // Adapt rho
502 if (work->settings->adaptive_rho &&
503 work->settings->adaptive_rho_interval &&
504 (iter % work->settings->adaptive_rho_interval == 0)) {
505 // Update info with the residuals if it hasn't been done before
506# ifdef PRINTING
507
508 if (!can_check_termination && !can_print) {
509 // Information has not been computed neither for termination or printing
510 // reasons
511 update_info(work, iter, compute_cost_function, 0);
512 }
513# else /* ifdef PRINTING */
514
515 if (!can_check_termination) {
516 // Information has not been computed before for termination check
517 update_info(work, iter, compute_cost_function, 0);
518 }
519# endif /* ifdef PRINTING */
520
521 // Actually update rho
522 if (adapt_rho(work)) {
523# ifdef PRINTING
524 c_eprint("Failed rho update");
525# endif // PRINTING
526 exitflag = 1;
527 goto exit;
528 }
529 }
530#endif // EMBEDDED != 1
531
532 } // End of ADMM for loop
533
534
535 // Update information and check termination condition if it hasn't been done
536 // during last iteration (max_iter reached or check_termination disabled)
537 if (!can_check_termination) {
538 /* Update information */
539#ifdef PRINTING
540
541 if (!can_print) {
542 // Update info only if it hasn't been updated before for printing
543 // reasons
544 update_info(work, iter - 1, compute_cost_function, 0);
545 }
546#else /* ifdef PRINTING */
547
548 // If no printing is enabled, update info directly
549 update_info(work, iter - 1, compute_cost_function, 0);
550#endif /* ifdef PRINTING */
551
552#ifdef PRINTING
553
554 /* Print summary */
555 if (work->settings->verbose && !work->summary_printed) print_summary(work);
556#endif /* ifdef PRINTING */
557
558 /* Check whether a termination criterion is triggered */
559 check_termination(work, 0);
560 }
561
562 // Compute objective value in case it was not
563 // computed during the iterations
564 if (!compute_cost_function && has_solution(work->info)){
565 work->info->obj_val = compute_obj_val(work, work->x);
566 }
567
568
569#ifdef PRINTING
570 /* Print summary for last iteration */
571 if (work->settings->verbose && !work->summary_printed) {
572 print_summary(work);
573 }
574#endif /* ifdef PRINTING */
575
576 /* if max iterations reached, change status accordingly */
577 if (work->info->status_val == OSQP_UNSOLVED) {
578 if (!check_termination(work, 1)) { // Try to check for approximate
579 update_status(work->info, OSQP_MAX_ITER_REACHED);
580 }
581 }
582
583#ifdef PROFILING
584 /* if time-limit reached check termination and update status accordingly */
585 if (work->info->status_val == OSQP_TIME_LIMIT_REACHED) {
586 if (!check_termination(work, 1)) { // Try for approximate solutions
587 update_status(work->info, OSQP_TIME_LIMIT_REACHED); /* Change update status back to OSQP_TIME_LIMIT_REACHED */
588 }
589 }
590#endif /* ifdef PROFILING */
591
592
593#if EMBEDDED != 1
594 /* Update rho estimate */
595 work->info->rho_estimate = compute_rho_estimate(work);
596#endif /* if EMBEDDED != 1 */
597
598 /* Update solve time */
599#ifdef PROFILING
600 work->info->solve_time = osqp_toc(work->timer);
601#endif /* ifdef PROFILING */
602
603
604#ifndef EMBEDDED
605 // Polish the obtained solution
606 if (work->settings->polish && (work->info->status_val == OSQP_SOLVED))
607 polish(work);
608#endif /* ifndef EMBEDDED */
609
610#ifdef PROFILING
611 /* Update total time */
612 if (work->first_run) {
613 // total time: setup + solve + polish
614 work->info->run_time = work->info->setup_time +
615 work->info->solve_time +
616 work->info->polish_time;
617 } else {
618 // total time: update + solve + polish
619 work->info->run_time = work->info->update_time +
620 work->info->solve_time +
621 work->info->polish_time;
622 }
623
624 // Indicate that the solve function has already been executed
625 if (work->first_run) work->first_run = 0;
626
627 // Indicate that the update_time should be set to zero
628 work->clear_update_time = 1;
629
630 // Indicate that osqp_update_rho is not called from osqp_solve
631 work->rho_update_from_solve = 0;
632#endif /* ifdef PROFILING */
633
634#ifdef PRINTING
635 /* Print final footer */
636 if (work->settings->verbose) print_footer(work->info, work->settings->polish);
637#endif /* ifdef PRINTING */
638
639 // Store solution
640 store_solution(work);
641
642
643// Define exit flag for quitting function
644#if defined(PROFILING) || defined(CTRLC) || EMBEDDED != 1
645exit:
646#endif /* if defined(PROFILING) || defined(CTRLC) || EMBEDDED != 1 */
647
648#ifdef CTRLC
649 // Restore previous signal handler
650 osqp_end_interrupt_listener();
651#endif /* ifdef CTRLC */
652
653 return exitflag;
654}
655
656
657#ifndef EMBEDDED
658
659c_int osqp_cleanup(OSQPWorkspace *work) {
660 c_int exitflag = 0;
661
662 if (work) { // If workspace has been allocated
663 // Free Data
664 if (work->data) {
665 if (work->data->P) csc_spfree(work->data->P);
666 if (work->data->A) csc_spfree(work->data->A);
667 if (work->data->q) c_free(work->data->q);
668 if (work->data->l) c_free(work->data->l);
669 if (work->data->u) c_free(work->data->u);
670 c_free(work->data);
671 }
672
673 // Free scaling variables
674 if (work->scaling){
675 if (work->scaling->D) c_free(work->scaling->D);
676 if (work->scaling->Dinv) c_free(work->scaling->Dinv);
677 if (work->scaling->E) c_free(work->scaling->E);
678 if (work->scaling->Einv) c_free(work->scaling->Einv);
679 c_free(work->scaling);
680 }
681
682 // Free temp workspace variables for scaling
683 if (work->D_temp) c_free(work->D_temp);
684 if (work->D_temp_A) c_free(work->D_temp_A);
685 if (work->E_temp) c_free(work->E_temp);
686
687 // Free linear system solver structure
688 if (work->linsys_solver) {
689 if (work->linsys_solver->free) {
690 work->linsys_solver->free(work->linsys_solver);
691 }
692 }
693
694 // Unload linear system solver after free
695 if (work->settings) {
696 exitflag = unload_linsys_solver(work->settings->linsys_solver);
697 }
698
699#ifndef EMBEDDED
700 // Free active constraints structure
701 if (work->pol) {
702 if (work->pol->Alow_to_A) c_free(work->pol->Alow_to_A);
703 if (work->pol->Aupp_to_A) c_free(work->pol->Aupp_to_A);
704 if (work->pol->A_to_Alow) c_free(work->pol->A_to_Alow);
705 if (work->pol->A_to_Aupp) c_free(work->pol->A_to_Aupp);
706 if (work->pol->x) c_free(work->pol->x);
707 if (work->pol->z) c_free(work->pol->z);
708 if (work->pol->y) c_free(work->pol->y);
709 c_free(work->pol);
710 }
711#endif /* ifndef EMBEDDED */
712
713 // Free other Variables
714 if (work->rho_vec) c_free(work->rho_vec);
715 if (work->rho_inv_vec) c_free(work->rho_inv_vec);
716#if EMBEDDED != 1
717 if (work->constr_type) c_free(work->constr_type);
718#endif
719 if (work->x) c_free(work->x);
720 if (work->z) c_free(work->z);
721 if (work->xz_tilde) c_free(work->xz_tilde);
722 if (work->x_prev) c_free(work->x_prev);
723 if (work->z_prev) c_free(work->z_prev);
724 if (work->y) c_free(work->y);
725 if (work->Ax) c_free(work->Ax);
726 if (work->Px) c_free(work->Px);
727 if (work->Aty) c_free(work->Aty);
728 if (work->delta_y) c_free(work->delta_y);
729 if (work->Atdelta_y) c_free(work->Atdelta_y);
730 if (work->delta_x) c_free(work->delta_x);
731 if (work->Pdelta_x) c_free(work->Pdelta_x);
732 if (work->Adelta_x) c_free(work->Adelta_x);
733
734 // Free Settings
735 if (work->settings) c_free(work->settings);
736
737 // Free solution
738 if (work->solution) {
739 if (work->solution->x) c_free(work->solution->x);
740 if (work->solution->y) c_free(work->solution->y);
741 c_free(work->solution);
742 }
743
744 // Free information
745 if (work->info) c_free(work->info);
746
747# ifdef PROFILING
748 // Free timer
749 if (work->timer) c_free(work->timer);
750# endif /* ifdef PROFILING */
751
752 // Free work
753 c_free(work);
754 }
755
756 return exitflag;
757}
758
759#endif // #ifndef EMBEDDED
760
761
762/************************
763* Update problem data *
764************************/
765c_int osqp_update_lin_cost(OSQPWorkspace *work, const c_float *q_new) {
766
767 // Check if workspace has been initialized
768 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
769
770#ifdef PROFILING
771 if (work->clear_update_time == 1) {
772 work->clear_update_time = 0;
773 work->info->update_time = 0.0;
774 }
775 osqp_tic(work->timer); // Start timer
776#endif /* ifdef PROFILING */
777
778 // Replace q by the new vector
779 prea_vec_copy(q_new, work->data->q, work->data->n);
780
781 // Scaling
782 if (work->settings->scaling) {
783 vec_ew_prod(work->scaling->D, work->data->q, work->data->q, work->data->n);
784 vec_mult_scalar(work->data->q, work->scaling->c, work->data->n);
785 }
786
787 // Reset solver information
788 reset_info(work->info);
789
790#ifdef PROFILING
791 work->info->update_time += osqp_toc(work->timer);
792#endif /* ifdef PROFILING */
793
794 return 0;
795}
796
797c_int osqp_update_bounds(OSQPWorkspace *work,
798 const c_float *l_new,
799 const c_float *u_new) {
800 c_int i, exitflag = 0;
801
802 // Check if workspace has been initialized
803 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
804
805#ifdef PROFILING
806 if (work->clear_update_time == 1) {
807 work->clear_update_time = 0;
808 work->info->update_time = 0.0;
809 }
810 osqp_tic(work->timer); // Start timer
811#endif /* ifdef PROFILING */
812
813 // Check if lower bound is smaller than upper bound
814 for (i = 0; i < work->data->m; i++) {
815 if (l_new[i] > u_new[i]) {
816#ifdef PRINTING
817 c_eprint("lower bound must be lower than or equal to upper bound");
818#endif /* ifdef PRINTING */
819 return 1;
820 }
821 }
822
823 // Replace l and u by the new vectors
824 prea_vec_copy(l_new, work->data->l, work->data->m);
825 prea_vec_copy(u_new, work->data->u, work->data->m);
826
827 // Scaling
828 if (work->settings->scaling) {
829 vec_ew_prod(work->scaling->E, work->data->l, work->data->l, work->data->m);
830 vec_ew_prod(work->scaling->E, work->data->u, work->data->u, work->data->m);
831 }
832
833 // Reset solver information
834 reset_info(work->info);
835
836#if EMBEDDED != 1
837 // Update rho_vec and refactor if constraints type changes
838 exitflag = update_rho_vec(work);
839#endif // EMBEDDED != 1
840
841#ifdef PROFILING
842 work->info->update_time += osqp_toc(work->timer);
843#endif /* ifdef PROFILING */
844
845 return exitflag;
846}
847
848c_int osqp_update_lower_bound(OSQPWorkspace *work, const c_float *l_new) {
849 c_int i, exitflag = 0;
850
851 // Check if workspace has been initialized
852 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
853
854#ifdef PROFILING
855 if (work->clear_update_time == 1) {
856 work->clear_update_time = 0;
857 work->info->update_time = 0.0;
858 }
859 osqp_tic(work->timer); // Start timer
860#endif /* ifdef PROFILING */
861
862 // Replace l by the new vector
863 prea_vec_copy(l_new, work->data->l, work->data->m);
864
865 // Scaling
866 if (work->settings->scaling) {
867 vec_ew_prod(work->scaling->E, work->data->l, work->data->l, work->data->m);
868 }
869
870 // Check if lower bound is smaller than upper bound
871 for (i = 0; i < work->data->m; i++) {
872 if (work->data->l[i] > work->data->u[i]) {
873#ifdef PRINTING
874 c_eprint("upper bound must be greater than or equal to lower bound");
875#endif /* ifdef PRINTING */
876 return 1;
877 }
878 }
879
880 // Reset solver information
881 reset_info(work->info);
882
883#if EMBEDDED != 1
884 // Update rho_vec and refactor if constraints type changes
885 exitflag = update_rho_vec(work);
886#endif // EMBEDDED ! =1
887
888#ifdef PROFILING
889 work->info->update_time += osqp_toc(work->timer);
890#endif /* ifdef PROFILING */
891
892 return exitflag;
893}
894
895c_int osqp_update_upper_bound(OSQPWorkspace *work, const c_float *u_new) {
896 c_int i, exitflag = 0;
897
898 // Check if workspace has been initialized
899 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
900
901#ifdef PROFILING
902 if (work->clear_update_time == 1) {
903 work->clear_update_time = 0;
904 work->info->update_time = 0.0;
905 }
906 osqp_tic(work->timer); // Start timer
907#endif /* ifdef PROFILING */
908
909 // Replace u by the new vector
910 prea_vec_copy(u_new, work->data->u, work->data->m);
911
912 // Scaling
913 if (work->settings->scaling) {
914 vec_ew_prod(work->scaling->E, work->data->u, work->data->u, work->data->m);
915 }
916
917 // Check if upper bound is greater than lower bound
918 for (i = 0; i < work->data->m; i++) {
919 if (work->data->u[i] < work->data->l[i]) {
920#ifdef PRINTING
921 c_eprint("lower bound must be lower than or equal to upper bound");
922#endif /* ifdef PRINTING */
923 return 1;
924 }
925 }
926
927 // Reset solver information
928 reset_info(work->info);
929
930#if EMBEDDED != 1
931 // Update rho_vec and refactor if constraints type changes
932 exitflag = update_rho_vec(work);
933#endif // EMBEDDED != 1
934
935#ifdef PROFILING
936 work->info->update_time += osqp_toc(work->timer);
937#endif /* ifdef PROFILING */
938
939 return exitflag;
940}
941
942c_int osqp_warm_start(OSQPWorkspace *work, const c_float *x, const c_float *y) {
943
944 // Check if workspace has been initialized
945 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
946
947 // Update warm_start setting to true
948 if (!work->settings->warm_start) work->settings->warm_start = 1;
949
950 // Copy primal and dual variables into the iterates
951 prea_vec_copy(x, work->x, work->data->n);
952 prea_vec_copy(y, work->y, work->data->m);
953
954 // Scale iterates
955 if (work->settings->scaling) {
956 vec_ew_prod(work->scaling->Dinv, work->x, work->x, work->data->n);
957 vec_ew_prod(work->scaling->Einv, work->y, work->y, work->data->m);
958 vec_mult_scalar(work->y, work->scaling->c, work->data->m);
959 }
960
961 // Compute Ax = z and store it in z
962 mat_vec(work->data->A, work->x, work->z, 0);
963
964 return 0;
965}
966
967c_int osqp_warm_start_x(OSQPWorkspace *work, const c_float *x) {
968
969 // Check if workspace has been initialized
970 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
971
972 // Update warm_start setting to true
973 if (!work->settings->warm_start) work->settings->warm_start = 1;
974
975 // Copy primal variable into the iterate x
976 prea_vec_copy(x, work->x, work->data->n);
977
978 // Scale iterate
979 if (work->settings->scaling) {
980 vec_ew_prod(work->scaling->Dinv, work->x, work->x, work->data->n);
981 }
982
983 // Compute Ax = z and store it in z
984 mat_vec(work->data->A, work->x, work->z, 0);
985
986 return 0;
987}
988
989c_int osqp_warm_start_y(OSQPWorkspace *work, const c_float *y) {
990
991 // Check if workspace has been initialized
992 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
993
994 // Update warm_start setting to true
995 if (!work->settings->warm_start) work->settings->warm_start = 1;
996
997 // Copy dual variable into the iterate y
998 prea_vec_copy(y, work->y, work->data->m);
999
1000 // Scale iterate
1001 if (work->settings->scaling) {
1002 vec_ew_prod(work->scaling->Einv, work->y, work->y, work->data->m);
1003 vec_mult_scalar(work->y, work->scaling->c, work->data->m);
1004 }
1005
1006 return 0;
1007}
1008
1009
1010#if EMBEDDED != 1
1011
1012c_int osqp_update_P(OSQPWorkspace *work,
1013 const c_float *Px_new,
1014 const c_int *Px_new_idx,
1015 c_int P_new_n) {
1016 c_int i; // For indexing
1017 c_int exitflag; // Exit flag
1018 c_int nnzP; // Number of nonzeros in P
1019
1020 // Check if workspace has been initialized
1021 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1022
1023#ifdef PROFILING
1024 if (work->clear_update_time == 1) {
1025 work->clear_update_time = 0;
1026 work->info->update_time = 0.0;
1027 }
1028 osqp_tic(work->timer); // Start timer
1029#endif /* ifdef PROFILING */
1030
1031 nnzP = work->data->P->p[work->data->P->n];
1032
1033 if (Px_new_idx) { // Passing the index of elements changed
1034 // Check if number of elements is less or equal than the total number of
1035 // nonzeros in P
1036 if (P_new_n > nnzP) {
1037# ifdef PRINTING
1038 c_eprint("new number of elements (%i) greater than elements in P (%i)",
1039 (int)P_new_n,
1040 (int)nnzP);
1041# endif /* ifdef PRINTING */
1042 return 1;
1043 }
1044 }
1045
1046 if (work->settings->scaling) {
1047 // Unscale data
1048 unscale_data(work);
1049 }
1050
1051 // Update P elements
1052 if (Px_new_idx) { // Change only Px_new_idx
1053 for (i = 0; i < P_new_n; i++) {
1054 work->data->P->x[Px_new_idx[i]] = Px_new[i];
1055 }
1056 }
1057 else // Change whole P
1058 {
1059 for (i = 0; i < nnzP; i++) {
1060 work->data->P->x[i] = Px_new[i];
1061 }
1062 }
1063
1064 if (work->settings->scaling) {
1065 // Scale data
1066 scale_data(work);
1067 }
1068
1069 // Update linear system structure with new data
1070 exitflag = work->linsys_solver->update_matrices(work->linsys_solver,
1071 work->data->P,
1072 work->data->A);
1073
1074 // Reset solver information
1075 reset_info(work->info);
1076
1077# ifdef PRINTING
1078
1079 if (exitflag < 0) {
1080 c_eprint("new KKT matrix is not quasidefinite");
1081 }
1082# endif /* ifdef PRINTING */
1083
1084#ifdef PROFILING
1085 work->info->update_time += osqp_toc(work->timer);
1086#endif /* ifdef PROFILING */
1087
1088 return exitflag;
1089}
1090
1091
1092c_int osqp_update_A(OSQPWorkspace *work,
1093 const c_float *Ax_new,
1094 const c_int *Ax_new_idx,
1095 c_int A_new_n) {
1096 c_int i; // For indexing
1097 c_int exitflag; // Exit flag
1098 c_int nnzA; // Number of nonzeros in A
1099
1100 // Check if workspace has been initialized
1101 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1102
1103#ifdef PROFILING
1104 if (work->clear_update_time == 1) {
1105 work->clear_update_time = 0;
1106 work->info->update_time = 0.0;
1107 }
1108 osqp_tic(work->timer); // Start timer
1109#endif /* ifdef PROFILING */
1110
1111 nnzA = work->data->A->p[work->data->A->n];
1112
1113 if (Ax_new_idx) { // Passing the index of elements changed
1114 // Check if number of elements is less or equal than the total number of
1115 // nonzeros in A
1116 if (A_new_n > nnzA) {
1117# ifdef PRINTING
1118 c_eprint("new number of elements (%i) greater than elements in A (%i)",
1119 (int)A_new_n,
1120 (int)nnzA);
1121# endif /* ifdef PRINTING */
1122 return 1;
1123 }
1124 }
1125
1126 if (work->settings->scaling) {
1127 // Unscale data
1128 unscale_data(work);
1129 }
1130
1131 // Update A elements
1132 if (Ax_new_idx) { // Change only Ax_new_idx
1133 for (i = 0; i < A_new_n; i++) {
1134 work->data->A->x[Ax_new_idx[i]] = Ax_new[i];
1135 }
1136 }
1137 else { // Change whole A
1138 for (i = 0; i < nnzA; i++) {
1139 work->data->A->x[i] = Ax_new[i];
1140 }
1141 }
1142
1143 if (work->settings->scaling) {
1144 // Scale data
1145 scale_data(work);
1146 }
1147
1148 // Update linear system structure with new data
1149 exitflag = work->linsys_solver->update_matrices(work->linsys_solver,
1150 work->data->P,
1151 work->data->A);
1152
1153 // Reset solver information
1154 reset_info(work->info);
1155
1156# ifdef PRINTING
1157
1158 if (exitflag < 0) {
1159 c_eprint("new KKT matrix is not quasidefinite");
1160 }
1161# endif /* ifdef PRINTING */
1162
1163#ifdef PROFILING
1164 work->info->update_time += osqp_toc(work->timer);
1165#endif /* ifdef PROFILING */
1166
1167 return exitflag;
1168}
1169
1170
1171c_int osqp_update_P_A(OSQPWorkspace *work,
1172 const c_float *Px_new,
1173 const c_int *Px_new_idx,
1174 c_int P_new_n,
1175 const c_float *Ax_new,
1176 const c_int *Ax_new_idx,
1177 c_int A_new_n) {
1178 c_int i; // For indexing
1179 c_int exitflag; // Exit flag
1180 c_int nnzP, nnzA; // Number of nonzeros in P and A
1181
1182 // Check if workspace has been initialized
1183 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1184
1185#ifdef PROFILING
1186 if (work->clear_update_time == 1) {
1187 work->clear_update_time = 0;
1188 work->info->update_time = 0.0;
1189 }
1190 osqp_tic(work->timer); // Start timer
1191#endif /* ifdef PROFILING */
1192
1193 nnzP = work->data->P->p[work->data->P->n];
1194 nnzA = work->data->A->p[work->data->A->n];
1195
1196
1197 if (Px_new_idx) { // Passing the index of elements changed
1198 // Check if number of elements is less or equal than the total number of
1199 // nonzeros in P
1200 if (P_new_n > nnzP) {
1201# ifdef PRINTING
1202 c_eprint("new number of elements (%i) greater than elements in P (%i)",
1203 (int)P_new_n,
1204 (int)nnzP);
1205# endif /* ifdef PRINTING */
1206 return 1;
1207 }
1208 }
1209
1210
1211 if (Ax_new_idx) { // Passing the index of elements changed
1212 // Check if number of elements is less or equal than the total number of
1213 // nonzeros in A
1214 if (A_new_n > nnzA) {
1215# ifdef PRINTING
1216 c_eprint("new number of elements (%i) greater than elements in A (%i)",
1217 (int)A_new_n,
1218 (int)nnzA);
1219# endif /* ifdef PRINTING */
1220 return 2;
1221 }
1222 }
1223
1224 if (work->settings->scaling) {
1225 // Unscale data
1226 unscale_data(work);
1227 }
1228
1229 // Update P elements
1230 if (Px_new_idx) { // Change only Px_new_idx
1231 for (i = 0; i < P_new_n; i++) {
1232 work->data->P->x[Px_new_idx[i]] = Px_new[i];
1233 }
1234 }
1235 else // Change whole P
1236 {
1237 for (i = 0; i < nnzP; i++) {
1238 work->data->P->x[i] = Px_new[i];
1239 }
1240 }
1241
1242 // Update A elements
1243 if (Ax_new_idx) { // Change only Ax_new_idx
1244 for (i = 0; i < A_new_n; i++) {
1245 work->data->A->x[Ax_new_idx[i]] = Ax_new[i];
1246 }
1247 }
1248 else { // Change whole A
1249 for (i = 0; i < nnzA; i++) {
1250 work->data->A->x[i] = Ax_new[i];
1251 }
1252 }
1253
1254 if (work->settings->scaling) {
1255 // Scale data
1256 scale_data(work);
1257 }
1258
1259 // Update linear system structure with new data
1260 exitflag = work->linsys_solver->update_matrices(work->linsys_solver,
1261 work->data->P,
1262 work->data->A);
1263
1264 // Reset solver information
1265 reset_info(work->info);
1266
1267# ifdef PRINTING
1268
1269 if (exitflag < 0) {
1270 c_eprint("new KKT matrix is not quasidefinite");
1271 }
1272# endif /* ifdef PRINTING */
1273
1274#ifdef PROFILING
1275 work->info->update_time += osqp_toc(work->timer);
1276#endif /* ifdef PROFILING */
1277
1278 return exitflag;
1279}
1280
1281c_int osqp_update_rho(OSQPWorkspace *work, c_float rho_new) {
1282 c_int exitflag, i;
1283
1284 // Check if workspace has been initialized
1285 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1286
1287 // Check value of rho
1288 if (rho_new <= 0) {
1289# ifdef PRINTING
1290 c_eprint("rho must be positive");
1291# endif /* ifdef PRINTING */
1292 return 1;
1293 }
1294
1295#ifdef PROFILING
1296 if (work->rho_update_from_solve == 0) {
1297 if (work->clear_update_time == 1) {
1298 work->clear_update_time = 0;
1299 work->info->update_time = 0.0;
1300 }
1301 osqp_tic(work->timer); // Start timer
1302 }
1303#endif /* ifdef PROFILING */
1304
1305 // Update rho in settings
1306 work->settings->rho = c_min(c_max(rho_new, RHO_MIN), RHO_MAX);
1307
1308 // Update rho_vec and rho_inv_vec
1309 for (i = 0; i < work->data->m; i++) {
1310 if (work->constr_type[i] == 0) {
1311 // Inequalities
1312 work->rho_vec[i] = work->settings->rho;
1313 work->rho_inv_vec[i] = 1. / work->settings->rho;
1314 }
1315 else if (work->constr_type[i] == 1) {
1316 // Equalities
1317 work->rho_vec[i] = RHO_EQ_OVER_RHO_INEQ * work->settings->rho;
1318 work->rho_inv_vec[i] = 1. / work->rho_vec[i];
1319 }
1320 }
1321
1322 // Update rho_vec in KKT matrix
1323 exitflag = work->linsys_solver->update_rho_vec(work->linsys_solver,
1324 work->rho_vec);
1325
1326#ifdef PROFILING
1327 if (work->rho_update_from_solve == 0)
1328 work->info->update_time += osqp_toc(work->timer);
1329#endif /* ifdef PROFILING */
1330
1331 return exitflag;
1332}
1333
1334#endif // EMBEDDED != 1
1335
1336/****************************
1337* Update problem settings *
1338****************************/
1339c_int osqp_update_max_iter(OSQPWorkspace *work, c_int max_iter_new) {
1340
1341 // Check if workspace has been initialized
1342 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1343
1344 // Check that max_iter is positive
1345 if (max_iter_new <= 0) {
1346#ifdef PRINTING
1347 c_eprint("max_iter must be positive");
1348#endif /* ifdef PRINTING */
1349 return 1;
1350 }
1351
1352 // Update max_iter
1353 work->settings->max_iter = max_iter_new;
1354
1355 return 0;
1356}
1357
1358c_int osqp_update_eps_abs(OSQPWorkspace *work, c_float eps_abs_new) {
1359
1360 // Check if workspace has been initialized
1361 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1362
1363 // Check that eps_abs is positive
1364 if (eps_abs_new < 0.) {
1365#ifdef PRINTING
1366 c_eprint("eps_abs must be nonnegative");
1367#endif /* ifdef PRINTING */
1368 return 1;
1369 }
1370
1371 // Update eps_abs
1372 work->settings->eps_abs = eps_abs_new;
1373
1374 return 0;
1375}
1376
1377c_int osqp_update_eps_rel(OSQPWorkspace *work, c_float eps_rel_new) {
1378
1379 // Check if workspace has been initialized
1380 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1381
1382 // Check that eps_rel is positive
1383 if (eps_rel_new < 0.) {
1384#ifdef PRINTING
1385 c_eprint("eps_rel must be nonnegative");
1386#endif /* ifdef PRINTING */
1387 return 1;
1388 }
1389
1390 // Update eps_rel
1391 work->settings->eps_rel = eps_rel_new;
1392
1393 return 0;
1394}
1395
1396c_int osqp_update_eps_prim_inf(OSQPWorkspace *work, c_float eps_prim_inf_new) {
1397
1398 // Check if workspace has been initialized
1399 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1400
1401 // Check that eps_prim_inf is positive
1402 if (eps_prim_inf_new < 0.) {
1403#ifdef PRINTING
1404 c_eprint("eps_prim_inf must be nonnegative");
1405#endif /* ifdef PRINTING */
1406 return 1;
1407 }
1408
1409 // Update eps_prim_inf
1410 work->settings->eps_prim_inf = eps_prim_inf_new;
1411
1412 return 0;
1413}
1414
1415c_int osqp_update_eps_dual_inf(OSQPWorkspace *work, c_float eps_dual_inf_new) {
1416
1417 // Check if workspace has been initialized
1418 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1419
1420 // Check that eps_dual_inf is positive
1421 if (eps_dual_inf_new < 0.) {
1422#ifdef PRINTING
1423 c_eprint("eps_dual_inf must be nonnegative");
1424#endif /* ifdef PRINTING */
1425 return 1;
1426 }
1427
1428 // Update eps_dual_inf
1429 work->settings->eps_dual_inf = eps_dual_inf_new;
1430
1431
1432 return 0;
1433}
1434
1435c_int osqp_update_alpha(OSQPWorkspace *work, c_float alpha_new) {
1436
1437 // Check if workspace has been initialized
1438 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1439
1440 // Check that alpha is between 0 and 2
1441 if ((alpha_new <= 0.) || (alpha_new >= 2.)) {
1442#ifdef PRINTING
1443 c_eprint("alpha must be between 0 and 2");
1444#endif /* ifdef PRINTING */
1445 return 1;
1446 }
1447
1448 // Update alpha
1449 work->settings->alpha = alpha_new;
1450
1451 return 0;
1452}
1453
1454c_int osqp_update_warm_start(OSQPWorkspace *work, c_int warm_start_new) {
1455
1456 // Check if workspace has been initialized
1457 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1458
1459 // Check that warm_start is either 0 or 1
1460 if ((warm_start_new != 0) && (warm_start_new != 1)) {
1461#ifdef PRINTING
1462 c_eprint("warm_start should be either 0 or 1");
1463#endif /* ifdef PRINTING */
1464 return 1;
1465 }
1466
1467 // Update warm_start
1468 work->settings->warm_start = warm_start_new;
1469
1470 return 0;
1471}
1472
1473c_int osqp_update_scaled_termination(OSQPWorkspace *work, c_int scaled_termination_new) {
1474
1475 // Check if workspace has been initialized
1476 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1477
1478 // Check that scaled_termination is either 0 or 1
1479 if ((scaled_termination_new != 0) && (scaled_termination_new != 1)) {
1480#ifdef PRINTING
1481 c_eprint("scaled_termination should be either 0 or 1");
1482#endif /* ifdef PRINTING */
1483 return 1;
1484 }
1485
1486 // Update scaled_termination
1487 work->settings->scaled_termination = scaled_termination_new;
1488
1489 return 0;
1490}
1491
1492c_int osqp_update_check_termination(OSQPWorkspace *work, c_int check_termination_new) {
1493
1494 // Check if workspace has been initialized
1495 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1496
1497 // Check that check_termination is nonnegative
1498 if (check_termination_new < 0) {
1499#ifdef PRINTING
1500 c_eprint("check_termination should be nonnegative");
1501#endif /* ifdef PRINTING */
1502 return 1;
1503 }
1504
1505 // Update check_termination
1506 work->settings->check_termination = check_termination_new;
1507
1508 return 0;
1509}
1510
1511#ifndef EMBEDDED
1512
1513c_int osqp_update_delta(OSQPWorkspace *work, c_float delta_new) {
1514
1515 // Check if workspace has been initialized
1516 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1517
1518 // Check that delta is positive
1519 if (delta_new <= 0.) {
1520# ifdef PRINTING
1521 c_eprint("delta must be positive");
1522# endif /* ifdef PRINTING */
1523 return 1;
1524 }
1525
1526 // Update delta
1527 work->settings->delta = delta_new;
1528
1529 return 0;
1530}
1531
1532c_int osqp_update_polish(OSQPWorkspace *work, c_int polish_new) {
1533
1534 // Check if workspace has been initialized
1535 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1536
1537 // Check that polish is either 0 or 1
1538 if ((polish_new != 0) && (polish_new != 1)) {
1539# ifdef PRINTING
1540 c_eprint("polish should be either 0 or 1");
1541# endif /* ifdef PRINTING */
1542 return 1;
1543 }
1544
1545 // Update polish
1546 work->settings->polish = polish_new;
1547
1548# ifdef PROFILING
1549
1550 // Reset polish time to zero
1551 work->info->polish_time = 0.0;
1552# endif /* ifdef PROFILING */
1553
1554 return 0;
1555}
1556
1557c_int osqp_update_polish_refine_iter(OSQPWorkspace *work, c_int polish_refine_iter_new) {
1558
1559 // Check if workspace has been initialized
1560 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1561
1562 // Check that polish_refine_iter is nonnegative
1563 if (polish_refine_iter_new < 0) {
1564# ifdef PRINTING
1565 c_eprint("polish_refine_iter must be nonnegative");
1566# endif /* ifdef PRINTING */
1567 return 1;
1568 }
1569
1570 // Update polish_refine_iter
1571 work->settings->polish_refine_iter = polish_refine_iter_new;
1572
1573 return 0;
1574}
1575
1576c_int osqp_update_verbose(OSQPWorkspace *work, c_int verbose_new) {
1577
1578 // Check if workspace has been initialized
1579 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1580
1581 // Check that verbose is either 0 or 1
1582 if ((verbose_new != 0) && (verbose_new != 1)) {
1583# ifdef PRINTING
1584 c_eprint("verbose should be either 0 or 1");
1585# endif /* ifdef PRINTING */
1586 return 1;
1587 }
1588
1589 // Update verbose
1590 work->settings->verbose = verbose_new;
1591
1592 return 0;
1593}
1594
1595#endif // EMBEDDED
1596
1597#ifdef PROFILING
1598
1599c_int osqp_update_time_limit(OSQPWorkspace *work, c_float time_limit_new) {
1600
1601 // Check if workspace has been initialized
1602 if (!work) return osqp_error(OSQP_WORKSPACE_NOT_INIT_ERROR);
1603
1604 // Check that time_limit is nonnegative
1605 if (time_limit_new < 0.) {
1606# ifdef PRINTING
1607 c_print("time_limit must be nonnegative\n");
1608# endif /* ifdef PRINTING */
1609 return 1;
1610 }
1611
1612 // Update time_limit
1613 work->settings->time_limit = time_limit_new;
1614
1615 return 0;
1616}
1617#endif /* ifdef PROFILING */