Skip to content

Commit

Permalink
Integer handling for feasible sets (#83)
Browse files Browse the repository at this point in the history
* code readability update

* Code cleanup

* Implemented has_integer for interval and FeasibleSet

* Created lp_integer_fits_int

* Created lp_feasibility_set_count_int

* Implement binary search for feasibility_set::contains

* fixed whitespaces

* Added comment

---------

Co-authored-by: Thomas Hader <[email protected]>
  • Loading branch information
Ovascos and Thomas Hader authored Oct 9, 2024
1 parent a614170 commit a79b13b
Show file tree
Hide file tree
Showing 17 changed files with 335 additions and 39 deletions.
15 changes: 15 additions & 0 deletions include/feasibility_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,26 @@ int lp_feasibility_set_is_full(const lp_feasibility_set_t* set);
*/
int lp_feasibility_set_is_point(const lp_feasibility_set_t* set);

/**
* Check if the set contains only one integer value.
*/
int lp_feasibility_set_is_point_int(const lp_feasibility_set_t* set);

/**
* Returns the number of integers in set (up to LONG_MAX).
*/
long lp_feasibility_set_count_int(const lp_feasibility_set_t* set);

/**
* Check if the given value belongs to the set.
*/
int lp_feasibility_set_contains(const lp_feasibility_set_t* set, const lp_value_t* value);

/**
* Checks if the set contains an integer value.
*/
int lp_feasibility_set_contains_int(const lp_feasibility_set_t* set);

/**
* Pick a value from the feasible set (must be non-empty). If an integer value
* is available it will be picked.
Expand Down
5 changes: 5 additions & 0 deletions include/integer.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ int lp_integer_print_matrix(const lp_integer_t* c_array, size_t m, size_t n, FIL
*/
char* lp_integer_to_string(const lp_integer_t* c);

/**
* Returns true if the integer fits in long.
*/
int lp_integer_fits_int(const lp_integer_t* c);

/**
* Returns the int representation of the integer (truncated but keeps sign).
*/
Expand Down
13 changes: 11 additions & 2 deletions include/interval.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ extern "C" {
#endif

/**
* An interval (a, b) with both point being values. This side is open is _open
* An interval (a, b) with both point being values. A side is open if _open
* is true. If interval is a point [a,a], then the value b is not used (it is
* not constructed).
*/
Expand Down Expand Up @@ -83,6 +83,12 @@ void lp_interval_swap(lp_interval_t* I1, lp_interval_t* I2);
/** Check if the value is contained in the interval */
int lp_interval_contains(const lp_interval_t* I, const lp_value_t* v);

/** Check if the interval contains an integer value */
int lp_interval_contains_int(const lp_interval_t* I);

/** Counts the number of integers in the interval (up to LONG_MAX) */
long lp_interval_count_int(const lp_interval_t* I);

/** Returns an approximation of the log interval size */
int lp_interval_size_approx(const lp_interval_t* I);

Expand Down Expand Up @@ -113,9 +119,12 @@ void lp_interval_pick_value(const lp_interval_t* I, lp_value_t* v);
/** Compares the lower bounds of the intervals */
int lp_interval_cmp_lower_bounds(const lp_interval_t* I1, const lp_interval_t* I2);

/** Compares the uppoer bounds of the intervals */
/** Compares the upper bounds of the intervals */
int lp_interval_cmp_upper_bounds(const lp_interval_t* I1, const lp_interval_t* I2);

/** Compares an interval I with a value v. Returns 0 if v in I, 1 if v is below I, -1 if v is above I. */
int lp_interval_cmp_value(const lp_interval_t* I, const lp_value_t* v);

/**
* Comparison of intervals based on upper bounds, with additional intersect info.
*/
Expand Down
4 changes: 4 additions & 0 deletions include/polyxx/interval.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ namespace poly {

/** Check whether an interval contains some value. */
bool contains(const Interval& i, const Value& v);
/** Check whether an interval contains an integer value. */
bool contains_int(const Interval& i);
/** Counts the number of integers in the interval up to LONG_MAX. */
long count_int(const Interval& i);
/** Get an approximation of the log interval size. */
int log_size(const Interval& i);

Expand Down
45 changes: 43 additions & 2 deletions python/polypyFeasibilitySet2.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,17 @@ FeasibilitySet_pick_value(PyObject* self);
static PyObject*
FeasibilitySet_intersect(PyObject* self, PyObject* args);

static PyObject*
FeasibilitySet_contains_value(PyObject* self, PyObject* args);

static PyObject*
FeasibilitySet_contains_int(PyObject* self);

PyMethodDef FeasibilitySet_methods[] = {
{"pick_value", (PyCFunction)FeasibilitySet_pick_value, METH_NOARGS, "Returns a value from the interval."},
{"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the interval with another one."},
{"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the set with another one."},
{"contains", (PyCFunction)FeasibilitySet_contains_value, METH_VARARGS, "Returns true if the value is in the feasibility set."},
{"contains_int", (PyCFunction)FeasibilitySet_contains_int, METH_NOARGS, "Returns true if the set contains an integer value."},
{NULL} /* Sentinel */
};

Expand Down Expand Up @@ -159,9 +167,42 @@ FeasibilitySet_intersect(PyObject* self, PyObject* args) {
lp_feasibility_set_t* S1 = ((FeasibilitySet*) self)->S;
lp_feasibility_set_t* S2 = ((FeasibilitySet*) feasibility_set_obj)->S;

// The intersect
// The intersection
lp_feasibility_set_t* P = lp_feasibility_set_intersect(S1, S2);
PyObject* P_obj = PyFeasibilitySet_create(P);

return P_obj;
}

static PyObject*
FeasibilitySet_contains_value(PyObject* self, PyObject* args) {

if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}

PyObject* value_obj = PyTuple_GetItem(args, 0);

if (!PyValue_CHECK(value_obj)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}

lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S;
lp_value_t* v = &((Value*) value_obj)->v;

int result = lp_feasibility_set_contains(S, v);

PyObject* result_object = result ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}

static PyObject*
FeasibilitySet_contains_int(PyObject* self) {
lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S;
PyObject* result_object = lp_feasibility_set_contains_int(S) ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}
51 changes: 45 additions & 6 deletions python/polypyFeasibilitySet3.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,17 @@ FeasibilitySet_pick_value(PyObject* self);
static PyObject*
FeasibilitySet_intersect(PyObject* self, PyObject* args);

static PyObject*
FeasibilitySet_contains_value(PyObject* self, PyObject* args);

static PyObject*
FeasibilitySet_contains_int(PyObject* self);

PyMethodDef FeasibilitySet_methods[] = {
{"pick_value", (PyCFunction)FeasibilitySet_pick_value, METH_NOARGS, "Returns a value from the interval."},
{"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the interval with another one."},
{"intersect", (PyCFunction)FeasibilitySet_intersect, METH_VARARGS, "Returns the intersection of the set with another one."},
{"contains", (PyCFunction)FeasibilitySet_contains_value, METH_VARARGS, "Returns true if the value is in the feasibility set."},
{"contains_int", (PyCFunction)FeasibilitySet_contains_int, METH_NOARGS, "Returns true if the set contains an integer value."},
{NULL} /* Sentinel */
};

Expand Down Expand Up @@ -98,8 +106,7 @@ PyTypeObject FeasibilitySetType = {
};

static void
FeasibilitySet_dealloc(FeasibilitySet* self)
{
FeasibilitySet_dealloc(FeasibilitySet* self) {
lp_feasibility_set_delete(self->S);
((PyObject*)self)->ob_type->tp_free((PyObject*)self);
}
Expand All @@ -120,8 +127,7 @@ FeasibilitySet_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
}

static int
FeasibilitySet_init(FeasibilitySet* self, PyObject* args)
{
FeasibilitySet_init(FeasibilitySet* self, PyObject* args) {
if (PyTuple_Check(args) && PyTuple_Size(args) == 0) {
// Defaults to (-inf, +inf)
self->S = lp_feasibility_set_new_full();
Expand Down Expand Up @@ -168,9 +174,42 @@ FeasibilitySet_intersect(PyObject* self, PyObject* args) {
lp_feasibility_set_t* S1 = ((FeasibilitySet*) self)->S;
lp_feasibility_set_t* S2 = ((FeasibilitySet*) feasibility_set_obj)->S;

// The intersect
// The intersection
lp_feasibility_set_t* P = lp_feasibility_set_intersect(S1, S2);
PyObject* P_obj = PyFeasibilitySet_create(P);

return P_obj;
}

static PyObject*
FeasibilitySet_contains_value(PyObject* self, PyObject* args) {

if (!PyTuple_Check(args) || PyTuple_Size(args) != 1) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}

PyObject* value_obj = PyTuple_GetItem(args, 0);

if (!PyValue_CHECK(value_obj)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}

lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S;
lp_value_t* v = &((Value*) value_obj)->v;

int result = lp_feasibility_set_contains(S, v);

PyObject* result_object = result ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}

static PyObject*
FeasibilitySet_contains_int(PyObject* self) {
lp_feasibility_set_t* S = ((FeasibilitySet*) self)->S;
PyObject* result_object = lp_feasibility_set_contains_int(S) ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}
14 changes: 12 additions & 2 deletions python/polypyInterval2.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ Interval_pick_value(PyObject* self);
static PyObject*
Interval_contains_value(PyObject* self, PyObject* args);

static PyObject*
Interval_contains_int(PyObject* self);

PyMethodDef Interval_methods[] = {
{"pick_value", (PyCFunction)Interval_pick_value, METH_NOARGS, "Returns a value from the interval."},
{"contains", (PyCFunction)Interval_contains_value, METH_VARARGS, "Returns true if the value is in the interval."},
{"contains_int", (PyCFunction)Interval_contains_int, METH_NOARGS, "Returns true if the interval contains an integer value."},
{NULL} /* Sentinel */
};

Expand Down Expand Up @@ -89,8 +93,7 @@ PyTypeObject IntervalType = {
};

static void
Interval_dealloc(Interval* self)
{
Interval_dealloc(Interval* self) {
lp_interval_destruct(&self->I);
self->ob_type->tp_free((PyObject*)self);
}
Expand Down Expand Up @@ -163,6 +166,13 @@ Interval_contains_value(PyObject* self, PyObject* args) {

PyObject* result_object = result ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}

static PyObject*
Interval_contains_int(PyObject* self) {
Interval* I = (Interval*) self;
PyObject* result_object = lp_interval_contains_int(&I->I) ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}
17 changes: 13 additions & 4 deletions python/polypyInterval3.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,13 @@ Interval_pick_value(PyObject* self);
static PyObject*
Interval_contains_value(PyObject* self, PyObject* args);

static PyObject*
Interval_contains_int(PyObject* self);

PyMethodDef Interval_methods[] = {
{"pick_value", (PyCFunction)Interval_pick_value, METH_NOARGS, "Returns a value from the interval."},
{"contains", (PyCFunction)Interval_contains_value, METH_VARARGS, "Returns true if the value is in the interval."},
{"contains_int", (PyCFunction)Interval_contains_int, METH_NOARGS, "Returns true if the interval contains an integer value."},
{NULL} /* Sentinel */
};

Expand Down Expand Up @@ -98,8 +102,7 @@ PyTypeObject IntervalType = {
};

static void
Interval_dealloc(Interval* self)
{
Interval_dealloc(Interval* self) {
lp_interval_destruct(&self->I);
((PyObject*)self)->ob_type->tp_free((PyObject*)self);
}
Expand All @@ -120,8 +123,7 @@ Interval_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
}

static int
Interval_init(Interval* self, PyObject* args)
{
Interval_init(Interval* self, PyObject* args) {
if (PyTuple_Check(args) && PyTuple_Size(args) == 0) {
// Defaults to (-inf, +inf)
lp_interval_construct_full(&self->I);
Expand Down Expand Up @@ -172,6 +174,13 @@ Interval_contains_value(PyObject* self, PyObject* args) {

PyObject* result_object = result ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}

static PyObject*
Interval_contains_int(PyObject* self) {
Interval* I = (Interval*) self;
PyObject* result_object = lp_interval_contains_int(&I->I) ? Py_True : Py_False;
Py_INCREF(result_object);
return result_object;
}
Loading

0 comments on commit a79b13b

Please sign in to comment.