(Correction: the characteristic we really care about is associativity,
not commutativity.)
I really shouldn't reply to this, because I fear this is just going to
drag me down into a bottomless pit, but here goes...
I don't see how unit tests can possibly help. There's an infinite number
of possible functions that could be passed to parallel reduce(), and you
can't test them all. Even if you lower your sights and just aim to
recognise a tiny subset of associative functions, you end up with code
like this:
def par_reduce(func, *args):
if func in (operator.add, operator.mul):
if isinstance(args[0], (int, long)):
return _associative_par_reduce(func, *args)
return _nonassociative_par_reduce(func, *args)
You can't even recognise functions like lambda x,y: x+y. In case you're
thinking you can, no, "if func == lambda x,y: x+y" won't work:
False
I suppose if you're willing to special case a tiny handful of functions,
that's a solution of sorts, but I did ask about arbitrary functions.
Perhaps you're thinking of another approach: put the unit tests inside
the par_reduce() function, and use them to determine at runtime whether
or not the argument func is associative.
def par_reduce(func, *args):
try:
# a mass of unittests
except Exception:
# are we catching too much? are we masking bugs in the tests?
return _nonassociative_par_reduce(func, *args)
return _associative_par_reduce(func, *args)
This would be impractical, because the cost would be enormous. But even
putting that aside, it still wouldn't work. I don't see how you could
know what is a valid unittest for an arbitrary function, but suppose you
could, somehow. Then what? True enough, if you run lots of tests, and it
fails one, then you know that func is not associative. But having passed
all those tests, you can't know if your tests covered all the possible
cases.
E.g. for floats, you can run some tests and decide that addition looks
associative:
True
but you'd be wrong:
False
No, you can't expect to discover experimentally whether an arbitrary
function is associative. You would need to analyse what the function
does, which means in practice the *programmer* needs to decide what to
do, not reduce().