Skip to content

Commit

Permalink
got it working
Browse files Browse the repository at this point in the history
  • Loading branch information
Steven Diamond committed Jan 6, 2016
1 parent 4410354 commit c394179
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 103 deletions.
4 changes: 2 additions & 2 deletions include/cmpb.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ int mpb_loadproblem(void *model, // model pointer
const double *b, // right-hand side vector
int64_t numconstrcones, // number of constraint cones
const int64_t *constrconetypes, // types of each constraint cone
const int64_t **constrconeindices, // vector of indices for each constraint cone
const int64_t *constrconeindices, // vector of indices for each constraint cone
const int64_t *constrconelengths, // number of indices in each constraint cone
int64_t numvarcones, // number of variable cones
const int64_t *varconetypes, // types of each variable cone
const int64_t **varconeindices, // vector of indices for each variable cone
const int64_t *varconeindices, // vector of indices for each variable cone
const int64_t *varconelengths // number of indices in each variable cone
);

Expand Down
84 changes: 38 additions & 46 deletions python/cmpb.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from ctypes import CDLL, POINTER, c_char, c_char_p, c_int, c_int64, \
c_double, c_void_p, byref
from numpy import int64, float64, ndarray, void
from numpy import int64, float64, ndarray, array, void, hstack
from os import uname, path
from site import getsitepackages
from scipy.sparse import coo_matrix
Expand Down Expand Up @@ -80,8 +80,8 @@ def ndarray_pointer(array):
lib.mpb_atexit.argtypes = [c_int]
lib.mpb_loadproblem.argtypes = [c_void_p, c_int64, c_int64, c_double_p,
c_int64_p, c_int64_p, c_double_p, c_int64, c_double_p,
c_int64, c_int64_p, POINTER(c_int64_p), c_int64_p,
c_int64, c_int64_p, POINTER(c_int64_p), c_int64_p]
c_int64, c_int64_p, c_int64_p, c_int64_p,
c_int64, c_int64_p, c_int64_p, c_int64_p]
lib.mpb_getsolution.argtypes = [c_void_p, c_double_p]
lib.mpb_getdual.argtypes = [c_void_p, c_double_p]
lib.mpb_status.argtypes = [c_void_p, c_char_p, c_int64]
Expand All @@ -98,7 +98,7 @@ def ndarray_pointer(array):
lib.mpb_free_solver.restype = c_int
lib.mpb_new_model.restype = c_int
lib.mpb_free_model.restype = c_int
lib.mpb_atexit = None
lib.mpb_atexit.restype = None
lib.mpb_loadproblem.restype = c_int
lib.mpb_getsolution.restype = c_int
lib.mpb_getdual.restype = c_int
Expand Down Expand Up @@ -134,35 +134,29 @@ def MPB_exit():
@param index_lists: list of lists of indices in each cone
'''
class MPBCones(object):
def __init__(self, types, index_lists):
def __init__(self, types, lengths, indices):
self.num = len(types)
self.types = int64(ndarray(types))
self.index_lists = [int64(ndarray(index_list)) for index_list in index_lists]
self.indices = ndarray(len(index_lists, c_int64_p))

for (i, ilist) in enumerate(self.index_lists):
self.indices[i] = ndarray_pointer(ilist)

lengths = [len(index_list) for index_list in index_lists]
self.lengths = int64(ndarray(lengths))
self.types = array(types).astype(int64)
self.indices = array(indices).astype(int64)
self.lengths = array(lengths).astype(int64)

self.type_ptr = ndarray_pointer(self.types)
self.index_ptr = narray_pointer(self.indices)
self.index_ptr = ndarray_pointer(self.indices)
self.length_ptr = ndarray_pointer(self.lengths)

'''
wrapper for MathProgBase solver
'''
class MPBSolver(object):
def __init__(self, packagename, solvername):
self.c = c_void_p()
self.ptr = c_void_p()
MPB_CHECKERR( lib.mpb_new_solver(
packagename, solvername, byref(self.c)) )
packagename, solvername, byref(self.ptr)) )

# automatically release solver when no
# references to MPBSolver object remain
def __del__(self):
MPB_CHECKERR( lib.mpb_free_solver(self.c) )
MPB_CHECKERR( lib.mpb_free_solver(self.ptr) )

'''
wrapper for MathProgBase model
Expand Down Expand Up @@ -217,22 +211,25 @@ def __init__(self, packagename, solvername,
self.solver = MPBSolver(packagename, solvername)

# initialize MathProgBase model
self.c = c_void_p()
MPB_CHECKERR( lib.mpb_new_model(self.solver.c, self.c) )
self.ptr = c_void_p()
MPB_CHECKERR( lib.mpb_new_model(self.solver.ptr, self.ptr) )

# load problem data into MathProgBase model
self.numvar = A.shape[1]
self.numconstr = A.shape[0]

row_ptr = ndarray_pointer(int64(A.row))
col_ptr = ndarray_pointer(int64(A.col))
data_ptr = ndarray_pointer(float64(A.data))
b_ptr = ndarray_pointer(float64(b))
c_ptr = ndarray_pointer(float64(c))
row_arr = A.row.astype(int64)
col_arr = A.col.astype(int64)
data_arr = A.data.astype(float64)
b_arr = b.astype(float64)
c_arr = c.astype(float64)

MPB_CHECKERR( lib.mpb_loadproblem(
self.numvar, self.numconstr, c_ptr,
row_ptr, col_ptr, data_ptr, A.nnz, b_ptr,
# import pdb; pdb.set_trace()

MPB_CHECKERR( lib.mpb_loadproblem(self.ptr,
self.numvar, self.numconstr, ndarray_pointer(c_arr),
ndarray_pointer(row_arr), ndarray_pointer(col_arr),
ndarray_pointer(data_arr), A.nnz, ndarray_pointer(b_arr),
constrcones.num, constrcones.type_ptr,
constrcones.index_ptr, constrcones.length_ptr,
varcones.num, varcones.type_ptr,
Expand All @@ -248,47 +245,47 @@ def __init__(self, packagename, solvername,
'''
def getproperty(self, property_name):
if property_name == "numvar":
call = lib.mpb_numvar
call = lib.mpb_getnumvar
dtype = int64
elif property_name == "numconstr":
call = lib.mpb_numconstr
call = lib.mpb_getnumconstr
dtype = int64
elif property_name == "objval":
call = lib.mpb_objval
call = lib.mpb_getobjval
dtype = float64
elif property_name == "objbound":
call = lib.mpb_objbound
call = lib.mpb_getobjbound
dtype = float64
elif property_name == "pbjgap":
call = lib.mpb_objgap
call = lib.mpb_getobjgap
dtype = float64
elif property_name == "solvetime":
call = lib.mpb_solvetime
call = lib.mpb_getsolvetime
dtype = float64
else:
print "invalid property key"

prop = ndarray(1, dtype=dtype)
MPB_CHECKERR( call(self.c, ndarray_pointer(prop)) )
MPB_CHECKERR( call(self.ptr, ndarray_pointer(prop)) )
return prop[0]

def getsolution(self):
MPB_CHECKERR( lib.mpb_getsolution(self.c,
MPB_CHECKERR( lib.mpb_getsolution(self.ptr,
ndarray_pointer(self.solution)) )
return self.solution

def getdual(self):
MPB_CHECKERR( lib.mpb_getsolution(self.c,
MPB_CHECKERR( lib.mpb_getsolution(self.ptr,
ndarray_pointer(self.dual)) )
return self.dual

def optimize(self):
MPB_CHECKERR( lib.mpb_optimize(self.c) )
MPB_CHECKERR( lib.mpb_optimize(self.ptr) )

def status(self):
len_buffer = STATUS_BUFFER_LENGTH
status_buffer = ndarray(len_buffer, dtype = c_char_p)
MPB_CHECKERR( lib.mpb_status(self.c,
status_buffer = ndarray(len_buffer, dtype = c_char)
MPB_CHECKERR( lib.mpb_status(self.ptr,
ndarray_pointer(status_buffer), len_buffer) )
return reduce(op_add, status_buffer)

Expand All @@ -297,11 +294,6 @@ def status(self):
# references to MPBModel object remain & exit MPB environment
def __del__(self):
del self.solver
MPB_CHECKERR( lib.mpb_free_model(self.c) )
MPB_CHECKERR( lib.mpb_free_model(self.ptr) )
MPB_exit()






102 changes: 54 additions & 48 deletions python/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,34 @@
c_int64_p = POINTER(c_int64)
c_double_p = POINTER(c_double)

# ----------------- problem data --------------------
nvar = 3
nconstr = 2
nnz = 5

c = np.float64(np.array([-3, -2, -4]))
b = np.float64(np.array([3, 2]))

def low_level():
# ----------------- problem data --------------------
nvar = 3
nconstr = 2
nnz = 5

I = np.array([0,0,1,0,1]).astype(np.int64)
J = np.array([0,1,1,2,2]).astype(np.int64)
V = np.array([1.0,1.0,1.0,1.0,1.0]).astype(np.float64)
c = np.float64(np.array([-3, -2, -4]))
b = np.float64(np.array([3, 2]))


numconstrcones = 1;
constrconetypes = np.array([ MPBZEROCONE ]).astype(np.int64)
constrconeindices1 = np.array([ 0, 1 ]).astype(np.int64)
constrconeindices = [ constrconeindices1 ]
constrconelengths = np.array([ 2 ]).astype(np.int64)
I = np.array([0,0,1,0,1]).astype(np.int64)
J = np.array([0,1,1,2,2]).astype(np.int64)
V = np.array([1.0,1.0,1.0,1.0,1.0]).astype(np.float64)

numvarcones = 1
varconetypes = np.array([ MPBNONNEGCONE ]).astype(np.int64)
varconeindices1 = np.array([ 0, 1, 2 ]).astype(np.int64)
varconeindices = [ varconeindices1 ]
varconelengths = np.array([ 3 ]).astype(np.int64)
# ---------------------------------------------------

numconstrcones = 1;
constrconetypes = np.array([ MPBZEROCONE ]).astype(np.int64)
constrconeindices = np.array([ 0, 1 ]).astype(np.int64)
# constrconeindices = [ constrconeindices1 ]
constrconelengths = np.array([ 2 ]).astype(np.int64)

numvarcones = 1
varconetypes = np.array([ MPBNONNEGCONE ]).astype(np.int64)
varconeindices = np.array([ 0, 1, 2 ]).astype(np.int64)
# varconeindices = [ varconeindices1 ]
varconelengths = np.array([ 3 ]).astype(np.int64)
# ---------------------------------------------------

def low_level():
# required: setup the julia context
lib.mpb_initialize();

Expand All @@ -47,24 +45,6 @@ def low_level():
lib.mpb_new_solver("ECOS","ECOSSolver()", byref(solver))
lib.mpb_new_model(solver, byref(model))

constr_idx_arr = np.zeros(numconstrcones, dtype=c_int64_p)
for i, idx_list in enumerate(constrconeindices):
tmp = idx_list.ctypes.data
constr_idx_arr[i] = tmp
print tmp
print constr_idx_arr.shape
# import pdb; pdb.set_trace()
# constr_idx_arr[i] = ndarray_pointer(np.array(idx_list).astype(np.int64))
constrconeindices_ptr = constr_idx_arr.ctypes.data_as(c_int64_pp)

var_idx_arr = np.zeros(numvarcones, dtype=c_int64_p)
for i, idx_list in enumerate(varconeindices):
var_idx_arr[i] = idx_list.ctypes.data
varconeindices_ptr = var_idx_arr.ctypes.data_as(c_int64_pp)

# I_arr = np.array(I).astype(np.int64)
# J_arr = np.array(J).astype(np.int64)
# V_arr = np.array(V).astype(np.float64)
err = lib.mpb_loadproblem(model, nvar, nconstr,
ndarray_pointer(c),
ndarray_pointer(I),
Expand All @@ -73,18 +53,18 @@ def low_level():
nnz, ndarray_pointer(b),
numconstrcones,
ndarray_pointer(constrconetypes),
constrconeindices_ptr,
ndarray_pointer(constrconeindices),
ndarray_pointer(constrconelengths),
numvarcones,
ndarray_pointer(varconetypes),
varconeindices_ptr,
ndarray_pointer(varconeindices),
ndarray_pointer(varconelengths));

assert err != 0
assert err == 0

err = lib.mpb_optimize(model);

assert err != 0
assert err == 0

status = np.ndarray(20, c_char)
ret = lib.mpb_status(model, status.ctypes.data_as(c_char_p), 20);
Expand All @@ -108,15 +88,41 @@ def low_level():
return 0

def high_level():
constrcones = MPBCones(constrconetypes, constrconeindices)
varcones = MPBCone(varconetypes, varconeindices)
# ----------------- problem data --------------------
nvar = 3
nconstr = 2
nnz = 5

c = np.array([-3, -2, -4])
b = np.array([3, 2])


I = [0,0,1,0,1]
J = [0,1,1,2,2]
V = [1.0,1.0,1.0,1.0,1.0]


numconstrcones = 1;
constrconetypes = [ MPBZEROCONE ]
constrconeindices = [ 0, 1 ]
# constrconeindices = [ constrconeindices1 ]
constrconelengths = [ 2 ]

numvarcones = 1
varconetypes = [ MPBNONNEGCONE ]
varconeindices = [ 0, 1, 2 ]
# varconeindices = [ varconeindices1 ]
varconelengths = [ 3 ]
# ---------------------------------------------------
constrcones = MPBCones(constrconetypes, constrconelengths, constrconeindices)
varcones = MPBCones(varconetypes, varconelengths, varconeindices)
A = coo_matrix((V, (I, J)), shape=(nconstr, nvar))

problem = MPBModel("ECOS", "ECOSSolver()", c, A, b,
constrcones, varcones)
problem.optimize()
print problem.status()
assert abs(problem.get("objval") - (-11)) < 1e-3
assert abs(problem.getproperty("objval") - (-11)) < 1e-3

sol = problem.getsolution()
assert abs(sol[0]-1.0) < 1e-3
Expand Down
13 changes: 6 additions & 7 deletions src/cmpb.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,20 +115,22 @@ jl_value_t* int_to_symbol(int64_t val) {

// MUST GC_PUSH the returned value
// Generates a vector with a list of cones, to be used as input for loadproblem!
jl_value_t* mpb_conevector(int64_t numcones, const int64_t *conetypes, const int64_t **coneindices, const int64_t *conelengths) {
jl_value_t* mpb_conevector(int64_t numcones, const int64_t *conetypes, const int64_t *coneindices, const int64_t *conelengths) {

jl_value_t *conevector = NULL, *indexvector = NULL, *conesymbol = NULL, *conetuple = NULL;
JL_GC_PUSH4(&conevector, &indexvector, &conesymbol, &conetuple);
conevector = jl_eval_string("Array(Tuple{Symbol,Any},0)");
jl_function_t *push_f = jl_get_function(jl_base_module, "push!");
int i;
int offset = 0;
for (i = 0; i < numcones; i++) {
conesymbol = int_to_symbol(conetypes[i]);
indexvector = mpb_ptr_to_intvec(coneindices[i], conelengths[i]);
indexvector = mpb_ptr_to_intvec(coneindices + offset, conelengths[i]);
conetuple = jl_new_struct(jl_eval_string("Tuple{Symbol,Vector{Int64}}"), conesymbol, indexvector);
assert(!jl_exception_occurred());
jl_call2(push_f, conevector, conetuple);
assert(!jl_exception_occurred());
offset = offset + conelengths[i];
}

JL_GC_POP();
Expand Down Expand Up @@ -269,14 +271,13 @@ int mpb_loadproblem(void *model, // model pointer
const double *b, // right-hand side vector
int64_t numconstrcones, // number of constraint cones
const int64_t *constrconetypes, // types of each constraint cone
const int64_t **constrconeindices, // vector of indices for each constraint cone
const int64_t *constrconeindices, // vector of indices for each constraint cone
const int64_t *constrconelengths, // number of indices in each constraint cone
int64_t numvarcones, // number of variable cones
const int64_t *varconetypes, // types of each variable cone
const int64_t **varconeindices, // vector of indices for each variable cone
const int64_t *varconeindices, // vector of indices for each variable cone
const int64_t *varconelengths // number of indices in each variable cone
) {

jl_value_t *cvec = NULL, *Amat = NULL, *bvec = NULL, *constr_cones = NULL,
*var_cones = NULL;
JL_GC_PUSH5(&cvec, &Amat, &bvec, &constr_cones, &var_cones);
Expand All @@ -293,8 +294,6 @@ int mpb_loadproblem(void *model, // model pointer
jl_value_t *loadargs[] = { (jl_value_t*)model, cvec, Amat, bvec, constr_cones, var_cones };

jl_call(loadproblem_f, loadargs, 6);
printf("varconeindices %u\n", varconeindices[0][1]);
jl_(jl_exception_occurred());
assert(!jl_exception_occurred());

JL_GC_POP();
Expand Down

11 comments on commit c394179

@mlubin
Copy link

@mlubin mlubin commented on c394179 Jan 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@bungun
Copy link
Owner

@bungun bungun commented on c394179 Jan 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still get this error when i try to run test.py

Assertion failed: (!jl_exception_occurred()), function mpb_initialize, file src/cmpb.c, line 172.

signal (6): Abort trap: 6
__pthread_kill at /usr/lib/system/libsystem_kernel.dylib (unknown line)
Abort trap: 6

@mlubin
Copy link

@mlubin mlubin commented on c394179 Jan 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bungun, make sure you've run import ECOS from a julia prompt first

@bungun
Copy link
Owner

@bungun bungun commented on c394179 Jan 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, Pkg.add("ECOS") and precompiling via import ECOS did the trick.

@mlubin
Copy link

@mlubin mlubin commented on c394179 Jan 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. This should be smoother once JuliaLang/julia#14577 is resolved.

@SteveDiamond
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm having a weird bug with other solvers:

Assertion failed: (!jl_exception_occurred()), function mpb_numvar, file src/cmpb.c, line 254.

signal (6): Abort trap: 6
__pthread_kill at /usr/lib/system/libsystem_kernel.dylib (unknown line)
[1]    69782 abort      python python/test.py

This happened for SCS and Cbc.

@mlubin
Copy link

@mlubin mlubin commented on c394179 Jan 6, 2016 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mlubin
Copy link

@mlubin mlubin commented on c394179 Jan 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SteveDiamond
Copy link
Collaborator

@SteveDiamond SteveDiamond commented on c394179 Jan 6, 2016 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SteveDiamond
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should Ipopt work? I get a massive error right now:

signal (11): Segmentation fault: 11
jl_method_table_assoc_exact at /Users/osx/buildbot/slave/package_osx10_9-x64/build/src/gf.c:251
jl_apply_generic at /Users/osx/buildbot/slave/package_osx10_9-x64/build/src/gf.c:1663
jl_apply at /Users/osx/buildbot/slave/package_osx10_9-x64/build/src/./julia.h:1325
mpb_objectid at /Users/stevend2/anaconda/lib/python2.7/site-packages/libcmpb.dylib (unknown line)
mpb_register_object at /Users/stevend2/anaconda/lib/python2.7/site-packages/libcmpb.dylib (unknown line)
mpb_new_model at /Users/stevend2/anaconda/lib/python2.7/site-packages/libcmpb.dylib (unknown line)
ffi_call_unix64 at /Users/stevend2/anaconda/lib/python2.7/lib-dynload/_ctypes.so (unknown line)
ffi_call at /Users/stevend2/anaconda/lib/python2.7/lib-dynload/_ctypes.so (unknown line)
_ctypes_callproc at /Users/stevend2/anaconda/lib/python2.7/lib-dynload/_ctypes.so (unknown line)
PyCFuncPtr_call at /Users/stevend2/anaconda/lib/python2.7/lib-dynload/_ctypes.so (unknown line)
PyObject_Call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyEval_EvalFrameEx at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyEval_EvalCodeEx at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
function_call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyObject_Call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
instancemethod_call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyObject_Call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
slot_tp_init at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
type_call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyObject_Call at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyEval_EvalFrameEx at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyEval_EvalFrameEx at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyEval_EvalCodeEx at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyEval_EvalCode at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyRun_FileExFlags at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
PyRun_SimpleFileExFlags at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
Py_Main at /Users/stevend2/anaconda/lib/libpython2.7.dylib (unknown line)
[1]    71318 segmentation fault  python python/test.py

@mlubin
Copy link

@mlubin mlubin commented on c394179 Jan 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that will need a bit more work. The translator from conic to nonlinear problems is here, but it's not in a working state currently.

Please sign in to comment.