Commit 012e6b5b authored by Tim Peters's avatar Tim Peters

Negative weights behave as documented now for weightedUnion and

weightedIntersection.
parent d9b60aaa
...@@ -314,9 +314,6 @@ class IIMerge(IMerge): ...@@ -314,9 +314,6 @@ class IIMerge(IMerge):
1 if the key is in c2 and c2 is a set 1 if the key is in c2 and c2 is a set
c2[key] if the key is in c2 and c2 is a mapping c2[key] if the key is in c2 and c2 is a mapping
XXX All of the above is wrong if either weight is negative. I think
XXX that's a bug in the implementation and will fix it.
Note that c1 and c2 must be collections. Note that c1 and c2 must be collections.
""" """
...@@ -348,9 +345,6 @@ class IIMerge(IMerge): ...@@ -348,9 +345,6 @@ class IIMerge(IMerge):
v2 is 1 if c2 is a set v2 is 1 if c2 is a set
c2[key] if c2 is a mapping c2[key] if c2 is a mapping
XXX All of the above is wrong if either weight is negative. I think
XXX that's a bug in the implementation and will fix it.
Note that c1 and c2 must be collections. Note that c1 and c2 must be collections.
""" """
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
Set operations Set operations
****************************************************************************/ ****************************************************************************/
#define SETOPTEMPLATE_C "$Id: SetOpTemplate.c,v 1.26 2002/06/25 22:02:27 tim_one Exp $\n" #define SETOPTEMPLATE_C "$Id: SetOpTemplate.c,v 1.27 2002/06/25 22:46:42 tim_one Exp $\n"
#ifdef INTSET_H #ifdef INTSET_H
static int static int
...@@ -198,8 +198,36 @@ copyRemaining(Bucket *r, SetIteration *i, int merge, int w) ...@@ -198,8 +198,36 @@ copyRemaining(Bucket *r, SetIteration *i, int merge, int w)
return 0; return 0;
} }
/* This is the workhorse for all set merge operations: the weighted and
* unweighted flavors of union and intersection, and set difference. The
* algorithm is conceptually simple but the code is complicated due to all
* the options.
*
* s1, s2
* The input collections to be merged.
*
* usevalues1, usevalues2
* Booleans. In the output, should values from s1 (or s2) be used? This
* only makes sense when an operation intends to support mapping outputs;
* these should both be false for operations that want pure set outputs.
*
* w1, w2
* If usevalues1(2) are true, these are the weights to apply to the
* input values.
*
* c1
* Boolean. Should keys that appear in c1 but not c2 appear in the output?
* c12
* Boolean. Should keys that appear in both inputs appear in the output?
* c2
* Boolean. Should keys that appear in c2 but not c1 appear in the output?
*
* Returns NULL if error, else a Set or Bucket, depending on whether a set or
* mapping was requested.
*/
static PyObject * static PyObject *
set_operation(PyObject *s1, PyObject *s2, set_operation(PyObject *s1, PyObject *s2,
int usevalues1, int usevalues2,
int w1, int w2, int w1, int w2,
int c1, int c12, int c2) int c1, int c12, int c2)
{ {
...@@ -207,8 +235,8 @@ set_operation(PyObject *s1, PyObject *s2, ...@@ -207,8 +235,8 @@ set_operation(PyObject *s1, PyObject *s2,
SetIteration i1 = {0,0,0}, i2 = {0,0,0}; SetIteration i1 = {0,0,0}, i2 = {0,0,0};
int cmp, merge; int cmp, merge;
if (initSetIteration(&i1, s1, w1 >= 0) < 0) goto err; if (initSetIteration(&i1, s1, usevalues1) < 0) goto err;
if (initSetIteration(&i2, s2, w2 >= 0) < 0) goto err; if (initSetIteration(&i2, s2, usevalues2) < 0) goto err;
merge = i1.usesValue | i2.usesValue; merge = i1.usesValue | i2.usesValue;
if (merge) if (merge)
...@@ -336,14 +364,16 @@ difference_m(PyObject *ignored, PyObject *args) ...@@ -336,14 +364,16 @@ difference_m(PyObject *ignored, PyObject *args)
UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL; UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL;
if (o1==Py_None || o2==Py_None) if (o1 == Py_None || o2 == Py_None)
{ {
/* difference(None, X) -> None; difference(X, None) -> X */ /* difference(None, X) -> None; difference(X, None) -> X */
Py_INCREF(o1); Py_INCREF(o1);
return o1; return o1;
} }
return set_operation(o1, o2, 1, -1, 1, 0, 0); return set_operation(o1, o2, 1, 0, /* preserve values from o1, ignore o2's */
1, 0, /* o1's values multiplied by 1 */
1, 0, 0); /* take only keys unique to o1 */
} }
static PyObject * static PyObject *
...@@ -358,13 +388,15 @@ union_m(PyObject *ignored, PyObject *args) ...@@ -358,13 +388,15 @@ union_m(PyObject *ignored, PyObject *args)
Py_INCREF(o2); Py_INCREF(o2);
return o2; return o2;
} }
else if (o2==Py_None) else if (o2 == Py_None)
{ {
Py_INCREF(o1); Py_INCREF(o1);
return o1; return o1;
} }
return set_operation(o1, o2, -1, -1, 1, 1, 1); return set_operation(o1, o2, 0, 0, /* ignore values in both */
1, 1, /* the weights are irrelevant */
1, 1, 1); /* take all keys */
} }
static PyObject * static PyObject *
...@@ -374,18 +406,20 @@ intersection_m(PyObject *ignored, PyObject *args) ...@@ -374,18 +406,20 @@ intersection_m(PyObject *ignored, PyObject *args)
UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL; UNLESS(PyArg_ParseTuple(args, "OO", &o1, &o2)) return NULL;
if (o1==Py_None) if (o1 == Py_None)
{ {
Py_INCREF(o2); Py_INCREF(o2);
return o2; return o2;
} }
else if (o2==Py_None) else if (o2 == Py_None)
{ {
Py_INCREF(o1); Py_INCREF(o1);
return o1; return o1;
} }
return set_operation(o1, o2, -1, -1, 0, 1, 0); return set_operation(o1, o2, 0, 0, /* ignore values in both */
1, 1, /* the weights are irrelevant */
0, 1, 0); /* take only keys common to both */
} }
#ifdef MERGE #ifdef MERGE
...@@ -394,16 +428,16 @@ static PyObject * ...@@ -394,16 +428,16 @@ static PyObject *
wunion_m(PyObject *ignored, PyObject *args) wunion_m(PyObject *ignored, PyObject *args)
{ {
PyObject *o1, *o2; PyObject *o1, *o2;
int w1=1, w2=1; int w1 = 1, w2 = 1;
UNLESS(PyArg_ParseTuple(args, "OO|ii", &o1, &o2, &w1, &w2)) return NULL; UNLESS(PyArg_ParseTuple(args, "OO|ii", &o1, &o2, &w1, &w2)) return NULL;
if (o1==Py_None) if (o1 == Py_None)
return Py_BuildValue("iO", (o2==Py_None ? 0 : w2), o2); return Py_BuildValue("iO", (o2 == Py_None ? 0 : w2), o2);
else if (o2==Py_None) else if (o2 == Py_None)
return Py_BuildValue("iO", w1, o1); return Py_BuildValue("iO", w1, o1);
o1=set_operation(o1, o2, w1, w2, 1, 1, 1); o1 = set_operation(o1, o2, 1, 1, w1, w2, 1, 1, 1);
if (o1) ASSIGN(o1, Py_BuildValue("iO", 1, o1)); if (o1) ASSIGN(o1, Py_BuildValue("iO", 1, o1));
return o1; return o1;
...@@ -413,16 +447,16 @@ static PyObject * ...@@ -413,16 +447,16 @@ static PyObject *
wintersection_m(PyObject *ignored, PyObject *args) wintersection_m(PyObject *ignored, PyObject *args)
{ {
PyObject *o1, *o2; PyObject *o1, *o2;
int w1=1, w2=1; int w1 = 1, w2 = 1;
UNLESS(PyArg_ParseTuple(args, "OO|ii", &o1, &o2, &w1, &w2)) return NULL; UNLESS(PyArg_ParseTuple(args, "OO|ii", &o1, &o2, &w1, &w2)) return NULL;
if (o1==Py_None) if (o1 == Py_None)
return Py_BuildValue("iO", (o2==Py_None ? 0 : w2), o2); return Py_BuildValue("iO", (o2 == Py_None ? 0 : w2), o2);
else if (o2==Py_None) else if (o2 == Py_None)
return Py_BuildValue("iO", w1, o1); return Py_BuildValue("iO", w1, o1);
o1=set_operation(o1, o2, w1, w2, 0, 1, 0); o1 = set_operation(o1, o2, 1, 1, w1, w2, 0, 1, 0);
if (o1) if (o1)
ASSIGN(o1, Py_BuildValue("iO", ASSIGN(o1, Py_BuildValue("iO",
((o1->ob_type == (PyTypeObject*)(&SetType)) ? w2+w1 : 1), ((o1->ob_type == (PyTypeObject*)(&SetType)) ? w2+w1 : 1),
......
...@@ -339,8 +339,8 @@ class Weighted(TestCase): ...@@ -339,8 +339,8 @@ class Weighted(TestCase):
self.emptys = [make([]) for make in self.builders] self.emptys = [make([]) for make in self.builders]
weights = [] weights = []
for w1 in 0, 1, 7: # -3, -1, 0, 1, 7: XXX negative weights buggy for w1 in -3, -1, 0, 1, 7:
for w2 in 0, 1, 7: # -3, -1, 0, 1, 7: XXX negative weights buggy for w2 in -3, -1, 0, 1, 7:
weights.append((w1, w2)) weights.append((w1, w2))
self.weights = weights self.weights = weights
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment