| # Compatibility with Python 2 |
| from __future__ import print_function |
| |
| from scipy import sparse |
| import numpy as np |
| |
| |
| def write_int(f, x, name, *args): |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s = %i;\n" % (name, x)) |
| else: |
| f.write("c_int %s = %i;\n" % (name, x)) |
| |
| |
| def write_float(f, x, name, *args): |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s = %.20f;\n" % (name, x)) |
| else: |
| f.write("c_float %s = %.20f;\n" % (name, x)) |
| |
| |
| def write_vec_int(f, x, name, *args): |
| n = len(x) |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| else: |
| f.write("c_int * ") |
| f.write("%s = (c_int*) c_malloc(%i * sizeof(c_int));\n" % (name, n)) |
| |
| for i in range(n): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s[%i] = " % (name, i)) |
| f.write("%i;\n" % x[i]) |
| |
| |
| def write_vec_float(f, x, name, *args): |
| n = len(x) |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| else: |
| f.write("c_float * ") |
| f.write("%s = (c_float*) c_malloc(%i * sizeof(c_float));\n" % (name, n)) |
| |
| for i in range(n): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s[%i] = " % (name, i)) |
| if x[i] == np.inf: |
| f.write("OSQP_INFTY;\n") |
| elif x[i] == -np.inf: |
| f.write("-OSQP_INFTY;\n") |
| else: |
| f.write("%.20f;\n" % x[i]) |
| |
| |
| def clean_vec(f, name, *args): |
| f.write("c_free(") |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| # else: |
| # f.write("c_float * ") |
| f.write("%s);\n" % name) |
| |
| |
| def write_mat_sparse(f, A, name, *args): |
| m = A.shape[0] |
| n = A.shape[1] |
| |
| f.write("\n// Matrix " + name + "\n") |
| f.write("//") |
| f.write("-"*(len("Matrix ") + len(name)) + "\n") |
| |
| # Allocate Matrix |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| else: |
| f.write("csc * ") |
| f.write(name + " = (csc*) c_malloc(sizeof(csc));\n") |
| |
| # Write dimensions and number of nonzeros |
| if any(args): |
| write_int(f, m, "m", args, name) |
| write_int(f, n, "n", args, name) |
| write_int(f, -1, "nz", args, name) |
| write_int(f, A.nnz, "nzmax", args, name) |
| else: |
| write_int(f, m, "m", name) |
| write_int(f, n, "n", name) |
| write_int(f, -1, "nz", name) |
| write_int(f, A.nnz, "nzmax", name) |
| |
| for arg in args: |
| f.write("%s->" % arg) |
| if min(m,n) == 0: |
| f.write("%s->x = OSQP_NULL;\n" % name) |
| else: |
| f.write("%s->" % name) |
| f.write("x = (c_float*) c_malloc(%i * sizeof(c_float));\n" % A.nnz) |
| for i in range(A.nnz): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->" % name) |
| f.write("x[%i] = %.20f;\n" % (i, A.data[i])) |
| |
| for arg in args: |
| f.write("%s->" % arg) |
| if min(m,n) == 0: |
| f.write("%s->i = OSQP_NULL;\n" % name) |
| else: |
| f.write("%s->" % name) |
| f.write("i = (c_int*) c_malloc(%i * sizeof(c_int));\n" % A.nnz) |
| for i in range(A.nnz): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->" % name) |
| f.write("i[%i] = %i;\n" % (i, A.indices[i])) |
| |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->" % name) |
| f.write("p = (c_int*) c_malloc((%i + 1) * sizeof(c_int));\n" % n) |
| for i in range(A.shape[1] + 1): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->" % name) |
| f.write("p[%i] = %i;\n" % (i, A.indptr[i])) |
| |
| # Do the same for i and p |
| f.write("\n") |
| |
| |
| def clean_mat(f, name, *args): |
| |
| # Clean data vector |
| f.write("c_free(") |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->x);\n" % name) |
| |
| # Clean index vector |
| f.write("c_free(") |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->i);\n" % name) |
| |
| # Clean col pointer vector |
| f.write("c_free(") |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s->p);\n" % name) |
| |
| # Clean matrix |
| f.write("c_free(") |
| if any(args): |
| for arg in args: |
| f.write("%s->" % arg) |
| f.write("%s);\n" % name) |
| |
| |
| def generate_problem_data(P, q, A, l, u, problem_name, sols_data={}): |
| """ |
| Generate test problem data. |
| |
| The additional structure sols_data defines the additional vectors/scalars |
| we need to perform the tests |
| """ |
| # Get problem dimension |
| n = P.shape[0] |
| m = A.shape[0] |
| |
| # |
| # GENERATE HEADER FILE |
| # |
| f = open(problem_name + "/data.h", "w") |
| |
| # Add definition check |
| f.write("#ifndef " + problem_name.upper() + "_DATA_H\n") |
| f.write("#define " + problem_name.upper() + "_DATA_H\n") |
| |
| # Add Includes |
| f.write("#include \"osqp.h\"\n") |
| f.write("\n\n") |
| |
| # |
| # Create additional data structure |
| # |
| f.write("/* create additional data and solutions structure */\n") |
| f.write("typedef struct {\n") |
| # Generate further data and solutions |
| for key, value in sols_data.items(): |
| if isinstance(value, str): |
| # Status test get from C code |
| f.write("c_int %s;\n" % key) |
| # Check if it is an array or a scalar |
| elif isinstance(value, np.ndarray): |
| if isinstance(value.flatten(order='F')[0], int): |
| f.write("c_int * %s;\n" % key) |
| elif isinstance(value.flatten(order='F')[0], float): |
| f.write("c_float * %s;\n" % key) |
| else: |
| if isinstance(value, int): |
| f.write("c_int %s;\n" % key) |
| elif isinstance(value, float): |
| f.write("c_float %s;\n" % key) |
| f.write("} %s_sols_data;\n\n" % problem_name) |
| |
| # prototypes |
| f.write("/* function prototypes */\n") |
| f.write("OSQPData * generate_problem_%s();\n" % problem_name) |
| f.write("void clean_problem_%s(OSQPData * data);\n" % problem_name) |
| f.write("%s_sols_data * generate_problem_%s_sols_data();\n" % (problem_name, problem_name)) |
| f.write("void clean_problem_%s_sols_data(%s_sols_data * data);\n" % (problem_name, problem_name)) |
| f.write("\n\n") |
| |
| # |
| # Generate QP problem data |
| # |
| f.write("/* function to generate QP problem data */\n") |
| f.write("OSQPData * generate_problem_%s(){\n\n" % problem_name) |
| |
| # Initialize structure data |
| f.write("OSQPData * data = (OSQPData *)c_malloc(sizeof(OSQPData));\n\n") |
| |
| # Write problem dimensions |
| f.write("// Problem dimensions\n") |
| write_int(f, n, "n", "data") |
| write_int(f, m, "m", "data") |
| f.write("\n") |
| |
| # Write problem vectors |
| f.write("// Problem vectors\n") |
| write_vec_float(f, l, "l", "data") |
| write_vec_float(f, u, "u", "data") |
| write_vec_float(f, q, "q", "data") |
| f.write("\n") |
| |
| # Write matrix A |
| write_mat_sparse(f, A, "A", "data") |
| write_mat_sparse(f, P, "P", "data") |
| |
| # Return data and end function |
| f.write("return data;\n\n") |
| |
| f.write("}\n\n") |
| |
| |
| # |
| # Generate QP problem data |
| # |
| f.write("/* function to clean problem data structure */\n") |
| f.write("void clean_problem_%s(OSQPData * data){\n\n" % problem_name) |
| |
| # Free vectors |
| f.write("// Clean vectors\n") |
| clean_vec(f, "l", "data") |
| clean_vec(f, "u", "data") |
| clean_vec(f, "q", "data") |
| f.write("\n") |
| |
| # Free matrices |
| f.write("//Clean Matrices\n") |
| clean_mat(f, "A", "data") |
| clean_mat(f, "P", "data") |
| f.write("\n") |
| |
| f.write("c_free(data);\n\n") |
| |
| f.write("}\n\n") |
| |
| |
| |
| # |
| # Generate additional problem data for solutions |
| # |
| f.write("/* function to define solutions and additional data struct */\n") |
| f.write("%s_sols_data * generate_problem_%s_sols_data(){\n\n" % (problem_name, problem_name)) |
| |
| # Initialize structure data |
| f.write("%s_sols_data * data = (%s_sols_data *)c_malloc(sizeof(%s_sols_data));\n\n" % (problem_name, problem_name, problem_name)) |
| |
| |
| # Generate further data and solutions |
| for key, value in sols_data.items(): |
| if isinstance(value, str): |
| # Status test get from C code |
| if value == 'optimal': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_SOLVED')) |
| elif value == 'optimal_inaccurate': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_SOLVED_INACCURATE')) |
| elif value == 'primal_infeasible': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_PRIMAL_INFEASIBLE')) |
| elif value == 'primal_infeasible_inaccurate': |
| f.write("data->%s = %s;\n" % |
| (key, 'OSQP_PRIMAL_INFEASIBLE_INACCURATE')) |
| elif value == 'dual_infeasible': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_DUAL_INFEASIBLE')) |
| elif value == 'dual_infeasible_inaccurate': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_DUAL_INFEASIBLE_INACCURATE')) |
| |
| # Check if it is an array or a scalar |
| if type(value) is np.ndarray: |
| if isinstance(value.flatten(order='F')[0], int): |
| write_vec_int(f, value.flatten(order='F'), key, "data") |
| elif isinstance(value.flatten(order='F')[0], float): |
| write_vec_float(f, value.flatten(order='F'), key, "data") |
| else: |
| if isinstance(value, int): |
| write_int(f, value, key, "data") |
| elif isinstance(value, float): |
| write_float(f, value, key, "data") |
| |
| # Return data and end function |
| f.write("\nreturn data;\n\n") |
| |
| f.write("}\n\n") |
| |
| |
| |
| # |
| # Clean additional problem data for solutions |
| # |
| f.write("/* function to clean solutions and additional data struct */\n") |
| f.write("void clean_problem_%s_sols_data(%s_sols_data * data){\n\n" % (problem_name, problem_name)) |
| # Generate further data and solutions |
| for key, value in sols_data.items(): |
| # Check if it is an array or a scalar |
| if type(value) is np.ndarray: |
| clean_vec(f, key, "data") |
| |
| f.write("\nc_free(data);\n\n") |
| |
| f.write("}\n\n") |
| |
| f.write("#endif\n") |
| |
| f.close() |
| |
| |
| def generate_data(problem_name, sols_data): |
| """ |
| Generate test data vectors. |
| |
| The additional structure sols_data defines the additional vectors/scalars |
| we need to perform the tests |
| """ |
| |
| # |
| # GENERATE HEADER FILE |
| # |
| f = open(problem_name + "/data.h", "w") |
| |
| # Add definition check |
| f.write("#ifndef " + problem_name.upper() + "_DATA_H\n") |
| f.write("#define " + problem_name.upper() + "_DATA_H\n") |
| |
| # Add Includes |
| f.write("#include \"osqp.h\"\n") |
| f.write("\n\n") |
| |
| # |
| # Create additional data structure |
| # |
| f.write("/* create data and solutions structure */\n") |
| f.write("typedef struct {\n") |
| # Generate further data and solutions |
| for key, value in sols_data.items(): |
| if isinstance(value, str): |
| # Status test get from C code |
| f.write("c_int %s;\n" % key) |
| # Check if it is an array or a scalar |
| elif sparse.issparse(value): # Sparse matrix |
| f.write("csc * %s;\n" % key) |
| elif isinstance(value, np.ndarray): |
| if isinstance(value.flatten(order='F')[0], int): |
| f.write("c_int * %s;\n" % key) |
| elif isinstance(value.flatten(order='F')[0], float): |
| f.write("c_float * %s;\n" % key) |
| else: |
| if isinstance(value, int): |
| f.write("c_int %s;\n" % key) |
| elif isinstance(value, float): |
| f.write("c_float %s;\n" % key) |
| f.write("} %s_sols_data;\n\n" % problem_name) |
| |
| # prototypes |
| f.write("/* function prototypes */\n") |
| f.write("%s_sols_data * generate_problem_%s_sols_data();\n" % (problem_name, problem_name)) |
| f.write("void clean_problem_%s_sols_data(%s_sols_data * data);\n" % (problem_name, problem_name)) |
| f.write("\n\n") |
| |
| # |
| # Generate additional problem data for solutions |
| # |
| f.write("/* function to define problem data */\n") |
| f.write("%s_sols_data * generate_problem_%s_sols_data(){\n\n" % (problem_name, problem_name)) |
| |
| # Initialize structure data |
| f.write("%s_sols_data * data = (%s_sols_data *)c_malloc(sizeof(%s_sols_data));\n\n" % (problem_name, problem_name, problem_name)) |
| |
| # Generate further data and solutions |
| for key, value in sols_data.items(): |
| if isinstance(value, str): |
| # Status test get from C code |
| if value == 'optimal': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_SOLVED')) |
| elif value == 'primal_infeasible': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_PRIMAL_INFEASIBLE')) |
| elif value == 'dual_infeasible': |
| f.write("data->%s = %s;\n" % (key, 'OSQP_DUAL_INFEASIBLE')) |
| # Check if it is an array or a scalar |
| elif sparse.issparse(value): # Sparse matrix |
| write_mat_sparse(f, value, key, "data") |
| elif type(value) is np.ndarray: |
| if isinstance(value.flatten(order='F')[0], int): |
| write_vec_int(f, value.flatten(order='F'), key, "data") |
| elif isinstance(value.flatten(order='F')[0], float): |
| write_vec_float(f, value.flatten(order='F'), key, "data") |
| else: |
| if isinstance(value, int): |
| write_int(f, value, key, "data") |
| elif isinstance(value, float): |
| write_float(f, value, key, "data") |
| |
| # Return data and end function |
| f.write("\nreturn data;\n\n") |
| |
| f.write("}\n\n") |
| |
| |
| # |
| # Clean data |
| # |
| f.write("/* function to clean data struct */\n") |
| f.write("void clean_problem_%s_sols_data(%s_sols_data * data){\n\n" % (problem_name, problem_name)) |
| # Generate further data and solutions |
| for key, value in sols_data.items(): |
| # Check if it is an array or a scalar |
| if sparse.issparse(value): # Sparse matrix |
| clean_mat(f, key, "data") |
| elif type(value) is np.ndarray: |
| clean_vec(f, key, "data") |
| |
| f.write("\nc_free(data);\n\n") |
| |
| f.write("}\n\n") |
| |
| f.write("#endif\n") |
| |
| f.close() |