blob: cdf400ef99faaa0702ba7fcb815c40031c57930e [file] [log] [blame]
Austin Schuh9049e202022-02-20 17:34:16 -08001# Compatibility with Python 2
2from __future__ import print_function
3
4from scipy import sparse
5import numpy as np
6
7
8def write_int(f, x, name, *args):
9 if any(args):
10 for arg in args:
11 f.write("%s->" % arg)
12 f.write("%s = %i;\n" % (name, x))
13 else:
14 f.write("c_int %s = %i;\n" % (name, x))
15
16
17def write_float(f, x, name, *args):
18 if any(args):
19 for arg in args:
20 f.write("%s->" % arg)
21 f.write("%s = %.20f;\n" % (name, x))
22 else:
23 f.write("c_float %s = %.20f;\n" % (name, x))
24
25
26def write_vec_int(f, x, name, *args):
27 n = len(x)
28 if any(args):
29 for arg in args:
30 f.write("%s->" % arg)
31 else:
32 f.write("c_int * ")
33 f.write("%s = (c_int*) c_malloc(%i * sizeof(c_int));\n" % (name, n))
34
35 for i in range(n):
36 for arg in args:
37 f.write("%s->" % arg)
38 f.write("%s[%i] = " % (name, i))
39 f.write("%i;\n" % x[i])
40
41
42def write_vec_float(f, x, name, *args):
43 n = len(x)
44 if any(args):
45 for arg in args:
46 f.write("%s->" % arg)
47 else:
48 f.write("c_float * ")
49 f.write("%s = (c_float*) c_malloc(%i * sizeof(c_float));\n" % (name, n))
50
51 for i in range(n):
52 for arg in args:
53 f.write("%s->" % arg)
54 f.write("%s[%i] = " % (name, i))
55 if x[i] == np.inf:
56 f.write("OSQP_INFTY;\n")
57 elif x[i] == -np.inf:
58 f.write("-OSQP_INFTY;\n")
59 else:
60 f.write("%.20f;\n" % x[i])
61
62
63def clean_vec(f, name, *args):
64 f.write("c_free(")
65 if any(args):
66 for arg in args:
67 f.write("%s->" % arg)
68 # else:
69 # f.write("c_float * ")
70 f.write("%s);\n" % name)
71
72
73def write_mat_sparse(f, A, name, *args):
74 m = A.shape[0]
75 n = A.shape[1]
76
77 f.write("\n// Matrix " + name + "\n")
78 f.write("//")
79 f.write("-"*(len("Matrix ") + len(name)) + "\n")
80
81 # Allocate Matrix
82 if any(args):
83 for arg in args:
84 f.write("%s->" % arg)
85 else:
86 f.write("csc * ")
87 f.write(name + " = (csc*) c_malloc(sizeof(csc));\n")
88
89 # Write dimensions and number of nonzeros
90 if any(args):
91 write_int(f, m, "m", args, name)
92 write_int(f, n, "n", args, name)
93 write_int(f, -1, "nz", args, name)
94 write_int(f, A.nnz, "nzmax", args, name)
95 else:
96 write_int(f, m, "m", name)
97 write_int(f, n, "n", name)
98 write_int(f, -1, "nz", name)
99 write_int(f, A.nnz, "nzmax", name)
100
101 for arg in args:
102 f.write("%s->" % arg)
103 if min(m,n) == 0:
104 f.write("%s->x = OSQP_NULL;\n" % name)
105 else:
106 f.write("%s->" % name)
107 f.write("x = (c_float*) c_malloc(%i * sizeof(c_float));\n" % A.nnz)
108 for i in range(A.nnz):
109 for arg in args:
110 f.write("%s->" % arg)
111 f.write("%s->" % name)
112 f.write("x[%i] = %.20f;\n" % (i, A.data[i]))
113
114 for arg in args:
115 f.write("%s->" % arg)
116 if min(m,n) == 0:
117 f.write("%s->i = OSQP_NULL;\n" % name)
118 else:
119 f.write("%s->" % name)
120 f.write("i = (c_int*) c_malloc(%i * sizeof(c_int));\n" % A.nnz)
121 for i in range(A.nnz):
122 for arg in args:
123 f.write("%s->" % arg)
124 f.write("%s->" % name)
125 f.write("i[%i] = %i;\n" % (i, A.indices[i]))
126
127 for arg in args:
128 f.write("%s->" % arg)
129 f.write("%s->" % name)
130 f.write("p = (c_int*) c_malloc((%i + 1) * sizeof(c_int));\n" % n)
131 for i in range(A.shape[1] + 1):
132 for arg in args:
133 f.write("%s->" % arg)
134 f.write("%s->" % name)
135 f.write("p[%i] = %i;\n" % (i, A.indptr[i]))
136
137 # Do the same for i and p
138 f.write("\n")
139
140
141def clean_mat(f, name, *args):
142
143 # Clean data vector
144 f.write("c_free(")
145 if any(args):
146 for arg in args:
147 f.write("%s->" % arg)
148 f.write("%s->x);\n" % name)
149
150 # Clean index vector
151 f.write("c_free(")
152 if any(args):
153 for arg in args:
154 f.write("%s->" % arg)
155 f.write("%s->i);\n" % name)
156
157 # Clean col pointer vector
158 f.write("c_free(")
159 if any(args):
160 for arg in args:
161 f.write("%s->" % arg)
162 f.write("%s->p);\n" % name)
163
164 # Clean matrix
165 f.write("c_free(")
166 if any(args):
167 for arg in args:
168 f.write("%s->" % arg)
169 f.write("%s);\n" % name)
170
171
172def generate_problem_data(P, q, A, l, u, problem_name, sols_data={}):
173 """
174 Generate test problem data.
175
176 The additional structure sols_data defines the additional vectors/scalars
177 we need to perform the tests
178 """
179 # Get problem dimension
180 n = P.shape[0]
181 m = A.shape[0]
182
183 #
184 # GENERATE HEADER FILE
185 #
186 f = open(problem_name + "/data.h", "w")
187
188 # Add definition check
189 f.write("#ifndef " + problem_name.upper() + "_DATA_H\n")
190 f.write("#define " + problem_name.upper() + "_DATA_H\n")
191
192 # Add Includes
193 f.write("#include \"osqp.h\"\n")
194 f.write("\n\n")
195
196 #
197 # Create additional data structure
198 #
199 f.write("/* create additional data and solutions structure */\n")
200 f.write("typedef struct {\n")
201 # Generate further data and solutions
202 for key, value in sols_data.items():
203 if isinstance(value, str):
204 # Status test get from C code
205 f.write("c_int %s;\n" % key)
206 # Check if it is an array or a scalar
207 elif isinstance(value, np.ndarray):
208 if isinstance(value.flatten(order='F')[0], int):
209 f.write("c_int * %s;\n" % key)
210 elif isinstance(value.flatten(order='F')[0], float):
211 f.write("c_float * %s;\n" % key)
212 else:
213 if isinstance(value, int):
214 f.write("c_int %s;\n" % key)
215 elif isinstance(value, float):
216 f.write("c_float %s;\n" % key)
217 f.write("} %s_sols_data;\n\n" % problem_name)
218
219 # prototypes
220 f.write("/* function prototypes */\n")
221 f.write("OSQPData * generate_problem_%s();\n" % problem_name)
222 f.write("void clean_problem_%s(OSQPData * data);\n" % problem_name)
223 f.write("%s_sols_data * generate_problem_%s_sols_data();\n" % (problem_name, problem_name))
224 f.write("void clean_problem_%s_sols_data(%s_sols_data * data);\n" % (problem_name, problem_name))
225 f.write("\n\n")
226
227 #
228 # Generate QP problem data
229 #
230 f.write("/* function to generate QP problem data */\n")
231 f.write("OSQPData * generate_problem_%s(){\n\n" % problem_name)
232
233 # Initialize structure data
234 f.write("OSQPData * data = (OSQPData *)c_malloc(sizeof(OSQPData));\n\n")
235
236 # Write problem dimensions
237 f.write("// Problem dimensions\n")
238 write_int(f, n, "n", "data")
239 write_int(f, m, "m", "data")
240 f.write("\n")
241
242 # Write problem vectors
243 f.write("// Problem vectors\n")
244 write_vec_float(f, l, "l", "data")
245 write_vec_float(f, u, "u", "data")
246 write_vec_float(f, q, "q", "data")
247 f.write("\n")
248
249 # Write matrix A
250 write_mat_sparse(f, A, "A", "data")
251 write_mat_sparse(f, P, "P", "data")
252
253 # Return data and end function
254 f.write("return data;\n\n")
255
256 f.write("}\n\n")
257
258
259 #
260 # Generate QP problem data
261 #
262 f.write("/* function to clean problem data structure */\n")
263 f.write("void clean_problem_%s(OSQPData * data){\n\n" % problem_name)
264
265 # Free vectors
266 f.write("// Clean vectors\n")
267 clean_vec(f, "l", "data")
268 clean_vec(f, "u", "data")
269 clean_vec(f, "q", "data")
270 f.write("\n")
271
272 # Free matrices
273 f.write("//Clean Matrices\n")
274 clean_mat(f, "A", "data")
275 clean_mat(f, "P", "data")
276 f.write("\n")
277
278 f.write("c_free(data);\n\n")
279
280 f.write("}\n\n")
281
282
283
284 #
285 # Generate additional problem data for solutions
286 #
287 f.write("/* function to define solutions and additional data struct */\n")
288 f.write("%s_sols_data * generate_problem_%s_sols_data(){\n\n" % (problem_name, problem_name))
289
290 # Initialize structure data
291 f.write("%s_sols_data * data = (%s_sols_data *)c_malloc(sizeof(%s_sols_data));\n\n" % (problem_name, problem_name, problem_name))
292
293
294 # Generate further data and solutions
295 for key, value in sols_data.items():
296 if isinstance(value, str):
297 # Status test get from C code
298 if value == 'optimal':
299 f.write("data->%s = %s;\n" % (key, 'OSQP_SOLVED'))
300 elif value == 'optimal_inaccurate':
301 f.write("data->%s = %s;\n" % (key, 'OSQP_SOLVED_INACCURATE'))
302 elif value == 'primal_infeasible':
303 f.write("data->%s = %s;\n" % (key, 'OSQP_PRIMAL_INFEASIBLE'))
304 elif value == 'primal_infeasible_inaccurate':
305 f.write("data->%s = %s;\n" %
306 (key, 'OSQP_PRIMAL_INFEASIBLE_INACCURATE'))
307 elif value == 'dual_infeasible':
308 f.write("data->%s = %s;\n" % (key, 'OSQP_DUAL_INFEASIBLE'))
309 elif value == 'dual_infeasible_inaccurate':
310 f.write("data->%s = %s;\n" % (key, 'OSQP_DUAL_INFEASIBLE_INACCURATE'))
311
312 # Check if it is an array or a scalar
313 if type(value) is np.ndarray:
314 if isinstance(value.flatten(order='F')[0], int):
315 write_vec_int(f, value.flatten(order='F'), key, "data")
316 elif isinstance(value.flatten(order='F')[0], float):
317 write_vec_float(f, value.flatten(order='F'), key, "data")
318 else:
319 if isinstance(value, int):
320 write_int(f, value, key, "data")
321 elif isinstance(value, float):
322 write_float(f, value, key, "data")
323
324 # Return data and end function
325 f.write("\nreturn data;\n\n")
326
327 f.write("}\n\n")
328
329
330
331 #
332 # Clean additional problem data for solutions
333 #
334 f.write("/* function to clean solutions and additional data struct */\n")
335 f.write("void clean_problem_%s_sols_data(%s_sols_data * data){\n\n" % (problem_name, problem_name))
336 # Generate further data and solutions
337 for key, value in sols_data.items():
338 # Check if it is an array or a scalar
339 if type(value) is np.ndarray:
340 clean_vec(f, key, "data")
341
342 f.write("\nc_free(data);\n\n")
343
344 f.write("}\n\n")
345
346 f.write("#endif\n")
347
348 f.close()
349
350
351def generate_data(problem_name, sols_data):
352 """
353 Generate test data vectors.
354
355 The additional structure sols_data defines the additional vectors/scalars
356 we need to perform the tests
357 """
358
359 #
360 # GENERATE HEADER FILE
361 #
362 f = open(problem_name + "/data.h", "w")
363
364 # Add definition check
365 f.write("#ifndef " + problem_name.upper() + "_DATA_H\n")
366 f.write("#define " + problem_name.upper() + "_DATA_H\n")
367
368 # Add Includes
369 f.write("#include \"osqp.h\"\n")
370 f.write("\n\n")
371
372 #
373 # Create additional data structure
374 #
375 f.write("/* create data and solutions structure */\n")
376 f.write("typedef struct {\n")
377 # Generate further data and solutions
378 for key, value in sols_data.items():
379 if isinstance(value, str):
380 # Status test get from C code
381 f.write("c_int %s;\n" % key)
382 # Check if it is an array or a scalar
383 elif sparse.issparse(value): # Sparse matrix
384 f.write("csc * %s;\n" % key)
385 elif isinstance(value, np.ndarray):
386 if isinstance(value.flatten(order='F')[0], int):
387 f.write("c_int * %s;\n" % key)
388 elif isinstance(value.flatten(order='F')[0], float):
389 f.write("c_float * %s;\n" % key)
390 else:
391 if isinstance(value, int):
392 f.write("c_int %s;\n" % key)
393 elif isinstance(value, float):
394 f.write("c_float %s;\n" % key)
395 f.write("} %s_sols_data;\n\n" % problem_name)
396
397 # prototypes
398 f.write("/* function prototypes */\n")
399 f.write("%s_sols_data * generate_problem_%s_sols_data();\n" % (problem_name, problem_name))
400 f.write("void clean_problem_%s_sols_data(%s_sols_data * data);\n" % (problem_name, problem_name))
401 f.write("\n\n")
402
403 #
404 # Generate additional problem data for solutions
405 #
406 f.write("/* function to define problem data */\n")
407 f.write("%s_sols_data * generate_problem_%s_sols_data(){\n\n" % (problem_name, problem_name))
408
409 # Initialize structure data
410 f.write("%s_sols_data * data = (%s_sols_data *)c_malloc(sizeof(%s_sols_data));\n\n" % (problem_name, problem_name, problem_name))
411
412 # Generate further data and solutions
413 for key, value in sols_data.items():
414 if isinstance(value, str):
415 # Status test get from C code
416 if value == 'optimal':
417 f.write("data->%s = %s;\n" % (key, 'OSQP_SOLVED'))
418 elif value == 'primal_infeasible':
419 f.write("data->%s = %s;\n" % (key, 'OSQP_PRIMAL_INFEASIBLE'))
420 elif value == 'dual_infeasible':
421 f.write("data->%s = %s;\n" % (key, 'OSQP_DUAL_INFEASIBLE'))
422 # Check if it is an array or a scalar
423 elif sparse.issparse(value): # Sparse matrix
424 write_mat_sparse(f, value, key, "data")
425 elif type(value) is np.ndarray:
426 if isinstance(value.flatten(order='F')[0], int):
427 write_vec_int(f, value.flatten(order='F'), key, "data")
428 elif isinstance(value.flatten(order='F')[0], float):
429 write_vec_float(f, value.flatten(order='F'), key, "data")
430 else:
431 if isinstance(value, int):
432 write_int(f, value, key, "data")
433 elif isinstance(value, float):
434 write_float(f, value, key, "data")
435
436 # Return data and end function
437 f.write("\nreturn data;\n\n")
438
439 f.write("}\n\n")
440
441
442 #
443 # Clean data
444 #
445 f.write("/* function to clean data struct */\n")
446 f.write("void clean_problem_%s_sols_data(%s_sols_data * data){\n\n" % (problem_name, problem_name))
447 # Generate further data and solutions
448 for key, value in sols_data.items():
449 # Check if it is an array or a scalar
450 if sparse.issparse(value): # Sparse matrix
451 clean_mat(f, key, "data")
452 elif type(value) is np.ndarray:
453 clean_vec(f, key, "data")
454
455 f.write("\nc_free(data);\n\n")
456
457 f.write("}\n\n")
458
459 f.write("#endif\n")
460
461 f.close()