Elementwise equality! Given two dataframe columns or ndarrays, users often expect `==` to give out a column or ndarrays of bools (like `+`, ``, `*, `&`, and just about every other binary operator).
What I love about operator overloading is that now you can't use operators without looking at their definition, in which case.. you could have done numpy.equals(a, b) anyway.
Does a == b true, if all elements are the same? Does it return an array of booleans? It's anyone's guess!
The function call approach can be a lot less readable.
Consider using Shamir secret sharing to share a secret, D, among several people with two people required to recover the secret. D is a positive integer, such as a randomly generated 128 bit AES key you are using to encrypt your launch codes or credit card database.
For anyone not familiar with Shamir secret sharing what you do is pick a prime number, p, that is larger than D and another random positive integer A, that is less than p. Then give each person a pair of numbers, (i, (Ai + D) % p), where each person gets a different i (which should be a positive integer less than p...it is OK to simply use 1, 2, 3, ...). Let's let Di = (Ai + D) % p.
(This is for the case where you want any two people to be able to launch your missiles or decrypt your database. If you wanted 3 required instead of giving out (i, (Ai + D) % p) you would give out (i, (Bi^2 + Ai + D) % p) where B is a randomly chosen positive integer less than p. For 4 required add on a Ci^3 term, and so on).
Given (i, Di) and (j, Dj) and p it is possible to recover A and D.
Here's what that looks like in a language where the big int library uses an accumulator style, i.e., operations are of the form X = X op Y, where the ops are methods on the big int objects. Assume Bi and Bj are big int objects initialized from i and j, and Di and Dj are already big into objects, as is p. This particular example is using Perl. (This is very old code. Since 2002 you can add a "use bigint" pragma to Perl code and then it would look a lot more like the second Python example below).
my $A = $Dj->copy()->bsub($Di); # Dj-Di
$Di->bmul($Bj); # j*Di
$Dj->bmul($Bi); # i*Dj
$Di->bsub($Dj); # j*Di-i*Dj
$Bj->bsub($Bi); # j-i
$Bj->bmodinv($p); # (j-i)'
$Di->bmul($Bj); # (j*Di-i*Dj)*(j-i)'
$Di->bmod($p); # (j*Di-i*Dj)*(j-i)' mod p
$A->bmul($Bj); # (Dj-Di)*(j-i)'
$A->bmod($P); # (Dj-Di)*(j-i)' mod p
At this point, the recovered A is in $A and the recovered D is in $Di
Here's what it looks like in a language with the ops as function calls taking the big int objects as arguments. This example is Python without using operator overloading.
import operator as op
def recover(i, j, Di, Dj, p):
j_i_inv = pow(op.sub(j, i), -1, p)
A = op.mod(op.mul(op.sub(Dj, Di), j_i_inv), p)
D = op.mod(op.mul(op.sub(mul(j, Di), op.mul(i, Dj)), j_i_inv), p)
return A, D
Probably more readable than accumulator style. Here it is in Python using its built-in operator overloading for big ints:
def recover(i, j, Di, Dj, p):
j_i_inv = pow(j-i, -1, p)
A = ((Dj - Di) * j-i_inv ) % p
D = ((j*Di - i*Dj) * j_i_inv) % p
return A, D
I'd sure rather come across that than either of the earlier examples.
OT: this reminds me of something I started to do once but never finished. I was going to write for each language we used at work that had a big int library but that did not support operator overloading a class that implemented a big int RPN calculator. Java, for example. Then recover would look something like this:
calc = new BigRPNCalc();
calc.do(j, i, "-", p, "modinv dup");
calc.do(Dj, Di, "- *", p, "mod swap");
calc.do(j, Di, "*", i, Dj. "* - *", p, "mod");
D = calc.pop();
A = calc.pop();
But I never ended up needing big ints in any of those languages so never really got past some initial design work.
Does a == b true, if all elements are the same? Does it return an array of booleans? It's anyone's guess!