In [1]:
from collections import Counter
import numpy as np
class PrivateNumber():
def __init__(self, value, max_val, min_val):
self.value = value
self.max_val = max_val
self.min_val = min_val
def __add__(self, other):
# add to a private number
if(isinstance(other, PrivateNumber)):
entities = self.entities.union(other.entities)
new_val = self.value + other.value
entities = set(self.max_val.keys()).union(set(other.max_val.keys()))
new_max_val = {}
new_min_val = {}
for entity in entities:
self_max = self.max_val[entity] if entity in self.max_val else 0
other_max = other.max_val[entity] if entity in other.max_val else 0
self_min = self.min_val[entity] if entity in self.min_val else 0
other_min = other.min_val[entity] if entity in other.min_val else 0
new_max_val[entity] = self_max + other_max
new_min_val[entity] = self_min + other_min
else:
entities = self.entities
# add to a public number
new_val = self.value + other
new_max_val = {}
new_min_val = {}
for entity in entities:
new_max_val[entity] = self.max_val[entity] + other
new_min_val[entity] = self.min_val[entity] + other
return PrivateNumber(new_val,
new_max_val,
new_min_val)
def __mul__(self, other):
if(isinstance(other, PrivateNumber)):
new_self_max_val = {}
new_self_min_val = {}
for entity in self.entities:
# the biggest positive number this entity could contribute is when
# it is multiplied by the largest value of the same sign from other
new_self_max_val[entity] = max(self.min_val[entity] * other.xmin,
self.max_val[entity] * other.xmax)
# the smallest negative number this entity could contribute is when
# it is multiplied by the largest value of the opposite sign from other
new_self_min_val[entity] = min(self.min_val[entity] * other.xmax,
self.max_val[entity] * other.xmin)
new_other_max_val = {}
new_other_min_val = {}
for entity in other.entities:
# the biggest positive number this entity could contribute is when
# it is multiplied by the largest value of the same sign from other
new_other_max_val[entity] = max(other.min_val[entity] * self.xmin,
other.max_val[entity] * self.xmax)
# the smallest negative number this entity could contribute is when
# it is multiplied by the largest value of the opposite sign from other
new_other_min_val[entity] = min(other.min_val[entity] * self.xmax,
other.max_val[entity] * self.xmin)
new_max_val = {}
new_min_val = {}
for entity in self.entities:
left = new_self_max_val[entity] if entity in new_self_max_val else -(2**32)
right = new_other_max_val[entity] if entity in new_other_max_val else -(2**32)
new_max_val[entity] = max(left, right)
left = new_self_min_val[entity] if entity in new_self_min_val else 2**32
right = new_other_min_val[entity] if entity in new_other_min_val else 2**32
new_min_val[entity] = min(left, right)
return PrivateNumber(self.value * other.value,
new_max_val,
new_min_val)
new_max_val = {}
for entity in self.entities:
new_max_val[entity] = self.max_val[entity] * other
new_min_val = {}
for entity in self.entities:
new_min_val[entity] = self.min_val[entity] * other
if(other > 0):
return PrivateNumber(self.value * other,
new_max_val,
new_min_val)
else:
return PrivateNumber(self.value * other,
new_min_val,
new_max_val)
def __neg__(self):
return self * -1
def __sub__(self, other):
return self + (-other)
def __gt__(self, other):
if(isinstance(other, PrivateNumber)):
new_self_max_val = {}
new_self_min_val = {}
for entity in self.entities:
if not (self.min_val[entity] > other.xmax or self.max_val[entity] < other.xmin):
new_self_max_val[entity] = 1
else:
new_self_max_val[entity] = 0
new_self_min_val[entity] = 0
new_other_max_val = {}
new_other_min_val = {}
for entity in other.entities:
if not (other.min_val[entity] > self.xmax or other.max_val[entity] < self.xmin):
new_other_max_val[entity] = 1
else:
new_other_max_val[entity] = 0
new_other_min_val[entity] = 0
new_max_val = {}
new_min_val = {}
entities = self.entities.union(other.entities)
for entity in entities:
new_self_max = new_self_max_val[entity] if entity in new_self_max_val else -999999999
new_other_max = new_other_max_val[entity] if entity in new_other_max_val else -999999999
new_self_min = new_self_min_val[entity] if entity in new_self_min_val else 99999999
new_other_min = new_other_min_val[entity] if entity in new_other_min_val else 99999999
new_max_val[entity] = max(new_self_max, new_other_max)
new_min_val[entity] = min(new_self_min, new_other_min)
result = int(self.value > other.value)
else:
entities = self.entities.union(other.entities)
new_max_val = {}
new_min_val = {}
for entity in entities:
new_min_val[entity] = 0
if(other <= self.max_val[entity] and other >= self.min_val[entity]):
new_max_val[entity] = 1
else:
new_max_val[entity] = 0
result = int(self.value > other)
return PrivateNumber(result,
new_max_val,
new_min_val)
def __lt__(self, other):
if(isinstance(other, PrivateNumber)):
entities = self.entities.union(other.entities)
new_self_max_val = {}
new_self_min_val = {}
for entity in self.entities:
if not (self.min_val[entity] > other.xmax or self.max_val[entity] < other.xmin):
new_self_max_val[entity] = 1
else:
new_self_max_val[entity] = 0
new_self_min_val[entity] = 0
new_other_max_val = {}
new_other_min_val = {}
for entity in other.entities:
if not (other.min_val[entity] > self.xmax or other.max_val[entity] < self.xmin):
new_other_max_val[entity] = 1
else:
new_other_max_val[entity] = 0
new_other_min_val[entity] = 0
new_max_val = {}
new_min_val = {}
entities = self.entities.union(other.entities)
for entity in entities:
new_self_max = new_self_max_val[entity] if entity in new_self_max_val else -999999999
new_other_max = new_other_max_val[entity] if entity in new_other_max_val else -999999999
new_self_min = new_self_min_val[entity] if entity in new_self_min_val else 99999999
new_other_min = new_other_min_val[entity] if entity in new_other_min_val else 99999999
new_max_val[entity] = max(new_self_max, new_other_max)
new_min_val[entity] = min(new_self_min, new_other_min)
result = int(self.value < other.value)
else:
entities = self.entities
new_max_val = {}
new_min_val = {}
for entity in entities:
new_min_val[entity] = 0
if(other <= self.max_val[entity] and other >= self.min_val[entity]):
new_max_val[entity] = 1
else:
new_max_val[entity] = 0
result = int(self.value < other)
return PrivateNumber(result,
new_max_val,
new_min_val)
def max(self, other):
if(isinstance(other, PrivateNumber)):
raise Exception("Not implemented yet")
entities = self.entities
new_min_val = {}
for entity in entities:
new_min_val[entity] = max(self.min_val[entity], other)
return PrivateNumber(max(self.value, other),
self.max_val,
new_min_val)
def min(self, other):
if(isinstance(other, PrivateNumber)):
raise Exception("Not implemented yet")
entities = self.entities
new_max_val = {}
for entity in entities:
new_max_val[entity] = min(self.max_val[entity], other)
return PrivateNumber(min(self.value, other),
new_max_val,
self.min_val)
def __repr__(self):
return str(self.value) + " " + str(self.max_val) + " " + str(self.min_val)
def hard_sigmoid(self):
return self.min(1).max(0)
def hard_sigmoid_deriv(self):
return ((self < 1) * (self > 0)) + (self < 0) * 0.01 - (self > 1) * 0.01
@property
def xmin(self):
items = list(self.min_val.items())
out = items[0][1]
for k,v in items[1:]:
out += v
return out
@property
def xmax(self):
items = list(self.max_val.items())
out = items[0][1]
for k,v in items[1:]:
out += v
return out
@property
def entities(self):
return set(self.max_val.keys())
@property
def max_sensitivity(self):
sens = Counter()
for entity, value in self.max_val.items():
sens[entity] = value - self.min_val[entity]
return sens.most_common()[0][1]
In [2]:
x = PrivateNumber(0.5,{"bob":4, "amos":3},{"bob":3, "amos":2})
x2 = PrivateNumber(0.5,{"bob":4, "amos":3},{"bob":3, "amos":2})
y = PrivateNumber(1,{"bob":1},{"bob":-1})
z = PrivateNumber(-0.5,{"sue":2},{"sue":-1})
In [4]:
x
Out[4]:
In [ ]:
In [78]:
a = (x * x2)# > y
In [79]:
a
Out[79]:
In [69]:
a.max_sensitivity
Out[69]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]: