below classes are in pure python, but the are a little slow on heavily dense calculation and lead to about 1 minute to do about 5 million action.
the question:
Is there any way to write them in C and import them to python for more speed?
how?
the usage is something like this:
_cm=Unit(...) # Unit
_m =Unit(...) # Unit
a= 1*_cm # UnitValue
b= 2*_m # UnitValue
_m2 = _m**2 # Unit
b*a == 0.02 * _m2 # UnitValue
a*b == 200 * _cm2 # UnitValue # _cm2 is auto created unit based on Unit.__new__
b-a = 0.99*_m # UnitValue
a-b = -99*_cm # UnitValue
# and so on...
NOTE: the classes are bigger that what included here...
class Unit(object):
def __new__(self, *args, **kwargs):
# check if this unit not created before and if ues return before created-one.
# useful for cmp between units.
return created_or_new_unit_instance
def __div__(self, other):
return self * (other ** -1) # self / other
def __rdiv__(self, other):
return other * (self ** -1) # other / self
def __rmul__(self, other):
return self * other # other * self
def __mul__(self, other): # self * other
if isinstance(other, SUPPORTED_NUMBERS):
return UnitValue(other, self)
elif isinstance(other, UnitValue): # FIXME DOUBLICATED!
return (other.value * (other.unit * self))
elif isinstance(other, Unit): # multipling two units self * other
# calculate the other exchange factor againest self in `v`
if v == 1.0:
# the bases may differ from self.bases or other.bases
# so just create a new Unit and let __new__ handle doublication.
return Unit(bases)
else:
return v * Unit(bases)
return NotImplemented
def __pow__(self, other, modulo=None): # #UnusedVariable
# create new powered unit.
return new Unit
and the other Class:
class UnitValue(object):
def __init__(self, value, unit):
self.value = value
self.unit = unit
def __add__(self, other): # self + other
if isinstance(other, UnitValue):
o = self.unit.get_unitvalue_in_this_unit(other) # other is UnitValue
v = self.value + o.value
return UnitValue(v, self.unit)
if other == 0:
return UnitValue(self.value, self.unit)
return NotImplemented
def __mul__(self, other): # self * other
if isinstance(other, SUPPORTED_NUMBERS):
return UnitValue(other * self.value, self.unit)
elif isinstance(other, UnitValue):
return (self.value * other.value) * (self.unit * other.unit)
return NotImplemented
def __pow__(self, other, modulo=None):
v = self.value ** other
u = self.unit ** other
if modulo:
v = v % modulo
return UnitValue(v, u)
def __cmp__(self, other):
if isinstance(other, UnitValue):
vo = self.unit.get_unitvalue_in_this_unit(other).value
else:
vo = other
if vo is None:
vo = 0
diff = self.value - vo
epsi = 1e-10
if abs(diff) < epsi: return 0
elif diff > 0: return 1
elif diff < 0: return -1
Related
I'm trying creating a 3D class Vector and I have prepared the following code:
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
#return string 'Vector(x,y,z)'
def __repr__(self):
return ("Vector(x,y,z)")
# or alternatively
#def __str__(self):
#return str("Vector3({0.x},{0.y},{0.z})".format(self))
# v == w
def __eq__(self, other):
self.v = Vector(self.x,self.y,self.z)
other.w = Vector(other.x, other.y, other.z)
if self.v() == self.w():
return True
else:
return False
#def __eq__(self, other): # poly1 == poly2
# return (self - other).is_zero() # it works when the substraction is defined
# v != w
def __ne__(self, other):
self.v = Vector(self.x,self.y,self.z)
other.w = Vector(other.x, other.y, other.z)
if self.v() != self.w():
return True
else:
return False
#def __ne__(self, other): # poly1 != poly2
# return not self == other
# v + w
def __add__(self, other):
if other == 0:
return self
else:
return vector(self.x+other.x, self.y+other.y, self.z+other.z)
# v - w
def __sub__(self, other):
self.x -= other.x
self.y -= other.y
self.z -= other.z
# return the dot product (number)
def __mul__(self, other):
self.v = Vector(self.x + self.y + self.z)
self.w = Vector(other.x + other.y + other.z)
return Vector(self.x*other.x,self.y*other.y, self.z*other.z)
#cross product
def __pow__(self, other):
return Vector(self.y*other.z - self.z*other.y,
self.z*other.x - self.x*other.z,
self.z*other.y - self.y*other.x)
# the length of the vector
def length(self):
return len(self)
# we assume that vectors are immutable
def __hash__(self):
return hash((self.x, self.y, self.z))
However no one of the following assert tests seem to work:
import math
v = Vector(1, 2, 3)
w = Vector(2, -3, 2)
assert v != w
assert v + w == Vector(3, -1, 5)
assert v - w == Vector(-1, 5, 1)
assert v * w == 2
assert v.cross(w) == Vector(13, 4, -7)
If someone tries running the following assert code, some errors pop up but I am not able to figure out what the problem is. Moreover, if it is possible I would lie to ask for a possible way to return the hash, length and string representation. Thanks
In part of my code I can subtract fractions, however if I enter (- p) where p is a fraction I get a TypeError: unsupported operand type(s) for +: "Fraction" and "Fraction"
def gcd(denominator, numerator):
if numerator == 0:
return denominator
else:
return gcd(numerator, (denominator % numerator))
class Fraction:
def __init__(self,numerator = 0, denominator = 1):
self.numerator = int(numerator / gcd(abs(denominator),abs(numerator) ))
self.denominator = int(denominator / gcd(abs(denominator),abs(numerator) ))
if self.denominator < 0:
self.denominator = abs(self.denominator)
self.numerator = -1*self.numerator
elif self.denominator == 0:
raise ZeroDivisionError
def __str__(self):
if self.denominator == 1:
return str(self.numerator)
else:
return str(self.numerator) + "/" + str(self.denominator)
def __rsub__(self,other):
return self.__sub__(other)
def __sub__(self,other):
if type(other) == int:
other = Fraction(other,1)
return self.sub(other)
else:
return self.sub(other)
def sub(self,other):
result = Fraction()
result.numerator = other.denominator * self.numerator - self.denominator * other.numerator
result.denominator = other.denominator * self.denominator
multiple = gcd(result.denominator,result.numerator)
result.numerator = int(result.numerator / multiple)
result.denominator = int(result.denominator / multiple)
return result
p = Fraction(2,3)
r = (- p)
However, when my input is (1 - p) I get the correct output. Suppose p = Fraction(2, 3) then I would like (- p) to return (-2 / 3) or (2/ -3). The problem seems to me to be in the fact that no input is given for the first argument when subtracting. While searching I did come across things like __neg__, but I'm still new to python and using classes so I don't know exactly how to implement this. Does anyone know how I can fix this?
Thanks in advance!
You are right; you need to implement __neg__ because that minus is not the (binary) subtraction operator, but the unary minus.
Here is how you can do it:
def __neg__(self):
return Fraction(-self.numerator, self.denominator)
Other issues
__rsub__
You need to change the implementation of __rsub__, because that method will be called when other does not support __sub__. For instance, it will kick in when you evaluate this:
p = 1 - Fraction(2, 3)
That evaluation will not work as it currently stands. You need to have this:
def __rsub__(self, other):
return Fraction(other) - self
or, explicitly calling __sub__:
def __rsub__(self, other):
return Fraction(other).__sub__(self)
Normalising
The constructor correctly normalises the fraction, making sure the denominator is positive, but you don't do the same in the sub method. There the result may not be normalised: the denominator could remain negative.
Moreover, it is a pity that you duplicate the gcd-related code that is already in the constructor. It is better to rely on the constructor for that logic.
Immutability
It is better to treat instances as immutable. So you should not have any assignments to instance.numerator and instance.denominator outside of the constructor. Make sure to first determine the numerator and denominator (without normalisation), and then call the constructor passing these as arguments.
Comparisons
You may want to compare Fractions for equality or relative order. For that you can implement __eq__, __lt__, ...etc.
Proposed code
Here is how I would do it:
def gcd(denominator, numerator):
if numerator == 0:
return denominator
else:
return gcd(numerator, denominator % numerator)
class Fraction:
def __new__(cls, numerator=0, denominator=1):
if isinstance(numerator, Fraction):
return numerator # Use this instance and ignore 2nd argument
return super(Fraction, cls).__new__(cls)
def __init__(self, numerator=0, denominator=1):
if isinstance(numerator, Fraction):
return # self is already initialised by __new__
if denominator == 0:
raise ZeroDivisionError
div = gcd(abs(denominator), abs(numerator))
if denominator < 0:
div = -div
self.numerator = numerator // div
self.denominator = denominator // div
def __str__(self):
if self.denominator == 1:
return str(self.numerator)
else:
return f"{self.numerator}/{self.denominator}"
def __rsub__(self, other):
return Fraction(other) - self
def __sub__(self, other):
other = Fraction(other)
return Fraction(other.denominator * self.numerator
- self.denominator * other.numerator,
other.denominator * self.denominator)
def __neg__(self):
return Fraction(-self.numerator, self.denominator)
def __eq__(self, other):
other = Fraction(other)
return (self.numerator == other.numerator and
self.denominator == other.denominator)
def __lt__(self, other):
other = Fraction(other)
return (other.denominator * self.numerator <
self.denominator * other.numerator)
def __gt__(self, other):
return Fraction(other) < self
def __le__(self, other):
return self < other or self == other
def __ge__(self, other):
return self > other or self == other
Your __rsub__ code is flipped, you want other.__sub__(self).
def __rsub__(self,other):
return other.__sub__(self)
I'm using this code to add two points together using finite Fields
class FieldElement():
def __init__(self,num,prime):
if num>=prime or num < 0:
error = "num s not in field"
raise ValueError(error)
self.num = num
self.prime=prime
def __eq__(self,other):
if other is None:
return
return self.num == other.num and self.prime == other.prime
def __ne__(self,other):
return not (self == other)
def __add__ (self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in diffirent fields")
num = (self.num+other.num)%self.prime
return self.__class__(num,self.prime)
def __mul__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (self.num * other.num)%self.prime
return self.__class__(num,self.prime)
def __pow__(self,exponent):
n = exponent%(self.prime-1)
num = pow(self.num,n,self.prime)
return self.__class__(num,self.prime)
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (other.num - self.num)%self.prime
return self.__class__(num,self.prime)
def __truediv__(self,other):
if self.prime != other.prime:
raise TypeError("cannot divide two numbers in different Fields")
num = self.num * pow(other.num,self.prime-2,self.prime)%self.prime
return self.__class__(num,self.prime)
class Point ():
def __init__(self, x,y,a,b):
self.a = a
self.b = b
self.y = y
self.x = x
if self.x is None and self.y is None:
return
if (self.y**2) != (self.x**3 + a*x + b):
raise ValueError("{} , {} not in the Curve".format(x.num,y.num))
def __repr__(self):
return "Point({},{}){}_{}".format(self.x,self.y,self.a,self.b)
def __eq__(self,other):
return self.x == other.x and self.y == other.y and self.a == other.a and self.b == other.b
def __add__(self,other):
if other.a != self.a or other.b != self.b:
raise TypeError("Points{},{} are the same curve".format(self,other))
if self.x is None:
return other
if other.x is None:
return self
if other.x == self.x and other.y != self.y:
return self.__class__(None,None,self.a,self.b)
if self != other:
s = (other.y-self.y)/(other.x-self.x)
x = (s**2 - self.x - other.x)
y = s*(self.x - x) - self.y
return self.__class__(x,y,self.a,self.b)
if self == other :
s = (3*self.x**2+self.a)/(2* self.y)
x = s**2-2*self.x
y = s*(self.x-x)-self.y
return self.__class__(x,y,self.a,self.b)
if self == other and self.y == 0*self.x:
return self.__class__(None,None,self.a,self.b)
def __eq__(self,other):
return self.x == other.x and self.y == other.y and self.a==other.a and self.b==other.b
def __mul__(self,other):
numX = self.x * other.x
numY = self.y * other.y
return self.__class__(numX,numY,self.a,self.b)
and the bellow code to test it ,
from test import FieldElement,Point
prime = 223
a = FieldElement(num=0,prime=prime)
b = FieldElement(num=7,prime=prime)
x1 = FieldElement(num=47,prime=prime)
y1 = FieldElement(num=71,prime=prime)
x2 = FieldElement(num=17,prime=prime)
y2 = FieldElement(num=56,prime=prime)
p1 = Point(x1,y1,a,b)
p2 = Point(x2,y2,a,b)
p3 = p1+p2
print(p3)
Whatever points I add I get the same error that the third point is not on the the curve, I think the problem is on if (self.y**2) != (self.x**3 + a*x + b) some how it's not checking the new point correctly or Point __add__ method does not calculate the new point correctly, what am missing here ?
You should test every module before use
In the Field, the subtraction is wrong! you calculate b-a not a-b
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (other.num - self.num)%self.prime
return self.__class__(num,self.prime)
must be
def __sub__(self,other):
if self.prime != other.prime:
raise ValueError("cannot add two numbers in different fields")
num = (self.num - other.num)%self.prime
return self.__class__(num,self.prime)
The other problem as stated in the other answer doesn't make a problem since the first operand is the member of the class, however, you should use
if (self.y**2) != (self.x**3 + self.a*self.x + self.b):
You should also implement __str__ for your field and point classes to print easy to test your code!
def __str__(self):
return num
I've tested and now works. The below is the SageMath Code (test here) that you can compare the result and use a test base for your code.
E = EllipticCurve(GF(223),[0,7])
print(E)
R1 = E(47,71)
R2 = E(17,56)
print(R1+R2)
I think that the line:
if (self.y**2) != (self.x**3 + a*x + b):
should be
if (self.y**2) != (self.x**3 + self.a*self.x + self.b):
as a, x and b will not be treated as field elements.
So I have to classes Swarm and Particles, and a class for Sphere function.
But when I'm trying to run the optimization, I get error on iteretation and I don't understand why:
TypeError: '<' not supported between instances of 'NoneType' and 'NoneType'
Eventually, if you can give me some tipf for shifted sphere function.
from abc import ABCMeta, abstractmethod
import numpy
import numpy.random
from particle import Particle
class Swarm (object):
__metaclass__ = ABCMeta
def __init__ (self,
swarmsize,
minvalues,
maxvalues,
currentVelocityRatio,
localVelocityRatio,
globalVelocityRatio):
self.__swarmsize = swarmsize
assert len (minvalues) == len (maxvalues)
assert (localVelocityRatio + globalVelocityRatio) > 4
self.__minvalues = numpy.array (minvalues[:])
self.__maxvalues = numpy.array (maxvalues[:])
self.__currentVelocityRatio = currentVelocityRatio
self.__localVelocityRatio = localVelocityRatio
self.__globalVelocityRatio = globalVelocityRatio
self.__globalBestFinalFunc = None
self.__globalBestPosition = None
self.__swarm = self.__createSwarm ()
def __getitem__ (self, index):
"""
Возвращает частицу с заданным номером
"""
return self.__swarm[index]
def __createSwarm (self):
return [Particle (self) for _ in range (self.__swarmsize) ]
def nextIteration (self):
for particle in self.__swarm:
return particle.nextIteration (self)
#property
def minvalues (self):
return self.__minvalues
#property
def maxvalues (self):
return self.__maxvalues
#property
def currentVelocityRatio (self):
return self.__currentVelocityRatio
#property
def localVelocityRatio (self):
return self.__localVelocityRatio
#property
def globalVelocityRatio (self):
return self.__globalVelocityRatio
#property
def globalBestPosition (self):
return self.__globalBestPosition
#property
def globalBestFinalFunc (self):
return self.__globalBestFinalFunc
def getFinalFunc (self, position):
assert len (position) == len (self.minvalues)
finalFunc = self._finalFunc (position)
if (self.__globalBestFinalFunc == None or
finalFunc < self.__globalBestFinalFunc):
self.__globalBestFinalFunc = finalFunc
self.__globalBestPosition = position[:]
#abstractmethod
def _finalFunc (self, position):
pass
#property
def dimension (self):
return len (self.minvalues)
def _getPenalty (self, position, ratio):
penalty1 = sum ([ratio * abs (coord - minval)
for coord, minval in zip (position, self.minvalues)
if coord < minval ] )
penalty2 = sum ([ratio * abs (coord - maxval)
for coord, maxval in zip (position, self.maxvalues)
if coord > maxval ] )
return penalty1 + penalty2
class Particle (object):
def __init__ (self, swarm):
self.__currentPosition = self.__getInitPosition (swarm)
self.__localBestPosition = self.__currentPosition[:]
self.__localBestFinalFunc = swarm.getFinalFunc (self.__currentPosition)
self.__velocity = self.__getInitVelocity (swarm)
#property
def position (self):
return self.__currentPosition
#property
def velocity (self):
return self.__velocity
def __getInitPosition (self, swarm):
return numpy.random.rand (swarm.dimension) * (swarm.maxvalues - swarm.minvalues) + swarm.minvalues
def __getInitVelocity (self, swarm):
assert len (swarm.minvalues) == len (self.__currentPosition)
assert len (swarm.maxvalues) == len (self.__currentPosition)
minval = -(swarm.maxvalues - swarm.minvalues)
maxval = (swarm.maxvalues - swarm.minvalues)
return numpy.random.rand (swarm.dimension) * (maxval - minval) + minval
def nextIteration (self, swarm):
rnd_currentBestPosition = numpy.random.rand (swarm.dimension)
rnd_globalBestPosition = numpy.random.rand (swarm.dimension)
veloRatio = swarm.localVelocityRatio + swarm.globalVelocityRatio
commonRatio = (2.0 * swarm.currentVelocityRatio /
(numpy.abs (2.0 - veloRatio - numpy.sqrt (veloRatio ** 2 - 4.0 * veloRatio) ) ) )
newVelocity_part1 = commonRatio * self.__velocity
newVelocity_part2 = (commonRatio *
swarm.localVelocityRatio *
rnd_currentBestPosition *
(self.__localBestPosition - self.__currentPosition) )
newVelocity_part3 = (commonRatio *
swarm.globalVelocityRatio *
rnd_globalBestPosition *
(swarm.globalBestPosition - self.__currentPosition) )
self.__velocity = newVelocity_part1 + newVelocity_part2 + newVelocity_part3
self.__currentPosition += self.__velocity
finalFunc = swarm.getFinalFunc (self.__currentPosition)
if finalFunc < self.__localBestFinalFunc:
self.__localBestPosition = self.__currentPosition[:]
self.__localBestFinalFunc = finalFunc
class Swarm_X2 (Swarm):
def init (self,
swarmsize,
minvalues,
maxvalues,
currentVelocityRatio,
localVelocityRatio,
globalVelocityRatio):
Swarm.init (self,
swarmsize,
minvalues,
maxvalues,
currentVelocityRatio,
localVelocityRatio,
globalVelocityRatio)
def _finalFunc (self, position):
penalty = self._getPenalty (position, 10000.0)
finalfunc = sum (position * position)
return finalfunc + penalty
from swarm_x2 import Swarm_X2
from utils import printResult
if name == "main":
iterCount = 300
dimension = 5
swarmsize = 200
minvalues = numpy.array ([-100] * dimension)
maxvalues = numpy.array ([100] * dimension)
currentVelocityRatio = 0.1
localVelocityRatio = 1.0
globalVelocityRatio = 5.0
swarm = Swarm_X2 (swarmsize,
minvalues,
maxvalues,
currentVelocityRatio,
localVelocityRatio,
globalVelocityRatio
)
for n in range (iterCount):
print "Position", swarm[0].position
print "Velocity", swarm[0].velocity
print printResult (swarm, n)
swarm.nextIteration()
Say we have a class AverageNumber which when adding, finds the mean of the numbers being added:
class AverageNumber():
def __init__(self, value):
self.value = value
def __add__(self, other):
average = ( self.value + other.value ) / 2 # This is the issue?
return AverageNumber(average)
def __str__(self):
return self.value
This code is incorrect, as it fails to respect the additive commutative and associative properties that I was looking for, namely that:
average(1 + 3 + 2) = average(1 + 2 + 3) etc.
However this does not occur, as the above class adds two at a time.
The INCORRECT results are below:
>>> b = AverageNumber(1) + AverageNumber(3) + AverageNumber(2)
>>> b.value
2.0
>>> b = AverageNumber(1) + AverageNumber(2) + AverageNumber(3)
>>> b.value
2.25
My question is: How can I modify the code above to fix this issue?
You just need to track the number of numbers involved:
class AverageNumber():
def __init__(self, value, count=1):
self.value = value
self.count = count
def __add__(self, other):
total = self.value + other.value
count = self.count + other.count
return AverageNumber(total, count)
def getValue(self):
return self.value / self.count
b = AverageNumber(1) + AverageNumber(3) + AverageNumber(2)
print(b.getValue())
b = AverageNumber(1) + AverageNumber(2) + AverageNumber(3)
print(b.getValue())
Output:
2.0
2.0