I am trying to write a simple implementation of elliptic curves in python.
So I have a simple Elliptic Curve class:
class EllipticCurve:
O ="O";
def __init__(self,a,b):
self.a = a
self.b = b
def __eq__(self, other):
if isinstance(other, EllipticCurve):
return self.a == other.a and self.b == other.b
return NotImplemented
def __ne__(self, other):
result = self.__eq__(other)
if result is NotImplemented:
return result
return not result
#property
def discriminant(self):
return 4*a**3+27*b**2
and a class for Points on an Elliptic Curves:
class Point:
def __init__(self,ec):
self.ec = ec
self = ec.O
def __init__(self,ec,x,y):
self.ec = ec
self.x = x
self.y = y
def __add__(self, other):
if self.ec != other.ec:
raise ValueError('These points are on different curves')
if self == self.ec.O:
return Point(ec, other.x, other.y)
if other == self.ec.O:
return Point(ec, self.x, self.y)
if self.x==other.x and self.y==-other.y:
return O
if self==other:
k = 3*(self.x**2+self.ec.a)/(2*self.y)
x3 = k**2-self.x-other.x
return Point(self.ec, x3,k*(self.x-x3)-self.y)
k = (other.y-self.y)/(other.x-self.x)
x3 = k ** 2 - self.x - other.x
return Point(self.ec, x3, k*(self.x - x3) - self.y)
def __eq__(self, other):
if isinstance(other, Point):
return self.x == other.x and self.y == other.y and self.ec == other.ec
return NotImplemented
def __ne__(self, other):
result = self.__eq__(other)
if result is NotImplemented:
return result
return not result
def __neg__(self):
if self==self.ec.O:
return O
return Point(E,self.x,-self.y)
def __sub__(self, other):
return self + -other
and although I would like to add some functionalities to them, they work with actual int values for a,b and x,y.
However, my problem is when I try to use sympy and use 'symbols' for a,b and x,y.
Ideally, my goal is to computationally prove the associative property for 3 points on an elliptic curve, ie, (P+Q)+R = P+(Q+R).
Now, I am able to get a correct result for P+Q:
a,b = symbols('a b')
x1,y1 = symbols('x1 y1')
x2,y2 = symbols('x2 y2')
x3,y3 = symbols('x3 y3')
E = EllipticCurve(a,b)
P = Point(E,x1,y1)
Q = Point(E,x2,y2)
R = Point(E,x3,y3)
P+Q
print(simplify((P+Q).x))
which outputs, correctly:
-x1 - x2 + (y1 - y2)**2/(x1 - x2)**2
Moreover, if I do this:
expr = (P+Q)+R
print(simplify(expr.x))
I get, also (I think) correctly:
x1 + x2 - x3 + (y1 + y3 - (y1 - y2)*(2*x1 + x2 - (y1 - y2)**2/(x1 - x2)**2)/(x1 - x2))**2/(x1 + x2 + x3 - (y1 - y2)**2/(x1 - x2)**2)**2 - (y1 - y2)**2/(x1 - x2)**2
However, if I do:
expr = (P+Q)+R
expr2 = P+(Q+R)
print(simplify((expr-expr2).x))
It takes forever, and if I try:
expr = (P+Q)+R
expr2 = P+(Q+R)
print((expr-expr2).x)
It also return an expression that seems reasonable and I think correct.
But I need to simplify it and to return 0 to prove that expr and expr2 are equal.
Any suggestions on what I am doing wrong ?
print((expr-expr2).x)
Probably you can't get 0 in a general case, because your result expression depends on x1, y1, x2, y2, x3, y3, which don't depend on each other, and if these points do not belong to the same elliptic curve, the result will not be 0. If you try to use (expr-expr2).x.subs ... using different args xi, yi, you can check that (expr-expr2).x is not zero constant.
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
The questions asks to "Write a method add_point that adds the position of the Point object given as an argument to the position of self". So far my code is this:
import math
epsilon = 1e-5
class Point(object):
"""A 2D point in the cartesian plane"""
def __init__(self, x, y):
"""
Construct a point object given the x and y coordinates
Parameters:
x (float): x coordinate in the 2D cartesian plane
y (float): y coordinate in the 2D cartesian plane
"""
self._x = x
self._y = y
def __repr__(self):
return 'Point({}, {})'.format(self._x, self._y)
def dist_to_point(self, other):
changex = self._x - other._x
changey = self._y - other._y
return math.sqrt(changex**2 + changey**2)
def is_near(self, other):
changex = self._x - other._x
changey = self._y - other._y
distance = math.sqrt(changex**2 + changey**2)
if distance < epsilon:
return True
def add_point(self, other):
new_x = self._x + other._x
new_y = self._y + other._y
new_point = new_x, new_y
return new_point
However, I got this error message:
Input: pt1 = Point(1, 2)
--------- Test 10 ---------
Expected Output: pt2 = Point(3, 4)
Test Result: 'Point(1, 2)' != 'Point(4, 6)'
- Point(1, 2)
? ^ ^
+ Point(4, 6)
? ^ ^
So I'm wondering what is the problem with my code?
Your solution returns a new tuple without modifying the attributes of the current object at all.
Instead, you need to actually change the object's attributes as per the instructions and don't need to return anything (ie, this is an "in-place" operation).
def add_point(self, other):
self._x += other._x
self._y += other._y
I made the following code to solve any quadratic polynomial but I want the final output to be a Real Number (Either a whole number or a fraction) but I get Complex numbers like (3+0j). How to convert them?
Here is the Code:-
import cmath
a = float(raw_input("Enter the Coefficient of x^2 :- "))
b = float(raw_input("Enter the coefficient of x :- "))
c = float(raw_input("Enter the value of constant term or c :- "))
d = ((b*b) - (4*a*c))
if d < 0:
print "There are no Real Roots of this equation"
else:
x1 = (((-b) + cmath.sqrt(float(d))) // 2*a)
x2 = (((-b) - cmath.sqrt(float(d))) // 2*a)
if x1 == x2:
print "x = ", x1
else:
print "x = ", x1, "or", x2
Desired Result:- I want the final result to be a Real Number(both Rational and irrational is allowed including fractions)(Like: 4, 4/3 or something like that).
Simply only print the real part, besides you have to devide by 2a
x1 = (((-b) + cmath.sqrt(float(d))) / (2*a))
x2 = (((-b) - cmath.sqrt(float(d))) / (2*a))
if x1 == x2:
print "x = ", x1.real
else:
print "x = ", x1.real, "or", x2.real
You can use a class like Complex and support imaginary solutions as well.
Code taken from http://hplgit.github.io/primer.html/doc/pub/class/._class-solarized005.html
class Complex(object):
def __init__(self, real, imag=0.0):
self.real = real
self.imag = imag
def __add__(self, other):
return Complex(self.real + other.real,
self.imag + other.imag)
def __sub__(self, other):
return Complex(self.real - other.real,
self.imag - other.imag)
def __mul__(self, other):
return Complex(self.real*other.real - self.imag*other.imag,
self.imag*other.real + self.real*other.imag)
def __div__(self, other):
sr, si, or, oi = self.real, self.imag, \
other.real, other.imag # short forms
r = float(or**2 + oi**2)
return Complex((sr*or+si*oi)/r, (si*or-sr*oi)/r)
def __abs__(self):
return sqrt(self.real**2 + self.imag**2)
def __neg__(self): # defines -c (c is Complex)
return Complex(-self.real, -self.imag)
def __eq__(self, other):
return self.real == other.real and self.imag == other.imag
def __ne__(self, other):
return not self.__eq__(other)
def __str__(self):
return '(%g, %g)' % (self.real, self.imag)
def __repr__(self):
return 'Complex' + str(self)
def __pow__(self, power):
raise NotImplementedError\
('self**power is not yet impl. for Complex')
G'day! When I know the slope and y-intercept of a line, I need to calculate an x-value that is 1 unit out from the line.
For example, if pointA = (4,5), and I set a line going from it with 0 slope (and therefore 5 as the y-intercept), then the x value I want would be 5. If the slope were undefined (vertical), then the x value would be 4. And so on.
So far, I calculate x as x = m(point[0]+1)-b. This doesn't work so well for vertical lines, however.
This and this are similar, but I can't read C# for the first, and on the second one, I don't need to eliminate any possible points (yet).
This is kind of hitting a nail with a sledge hammer, but if you're going to be running into geometry problems often, I'd either write or find a Point/Vector class like
import math
class Vector():
def __init__(self, x=0.0, y=0.0, z=0.0):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
self.x += other.x
self.y += other.y
self.z += other.z
return self
def __sub__(self, other):
self.x -= other.x
self.y -= other.y
self.z -= other.z
return self
def dot(self, other):
return self.x*other.x + self.y*other.y + self.z*other.z
def cross(self, other):
tempX = self.y*other.z - self.z*other.y
tempY = self.z*other.x - solf.x*other.z
tempZ = self.x*other.y - self.y*other.x
return Vector(tempX, tempY, tempZ)
def dist(self, other):
return math.sqrt((self.x-other.x)**2 + (self.y-other.y)**2 + (self.z-other.z)**2)
def unitVector(self):
mag = self.dist(Vector())
if mag != 0.0:
return Vector(self.x * 1.0/mag, self.y * 1.0/mag, self.z * 1.0/mag)
else:
return Vector()
def __repr__(self):
return str([self.x, self.y, self.z])
Then you can do all kinds of stuff like find the vector by subtracting two points
>>> a = Vector(4,5,0)
>>> b = Vector(5,6,0)
>>> b - a
[1, 1, 0]
Or adding an arbitrary unit vector to a point to find a new point (which is the answer to your original question)
>>> a = Vector(4,5,0)
>>> direction = Vector(10, 1, 0).unitVector()
>>> a + direction
[4.995037190209989, 5.099503719020999, 0.0]
You can add more utilities, like allowing Vector/Scalar operations for scaling, etc.
class Point:
def __init__(self, initX, initY):
""" Create a new point at the given coordinates. """
self.x = initX
self.y = initY
def getX(self):
return self.x
def getY(self):
return self.y
def distanceFromOrigin(self):
return ((self.x ** 2) + (self.y ** 2))** 0.5
def __str__(self):
return "x=" + str(self.x) + ", y=" + str(self.y)
def get_line_to(self, target):
mx = (-target.x + self.x )
my = (-target.y + self.y)
grad=my/mx
c=-(grad*(self.x))+self.y
return grad
def halfway(self, target):
"""calculating midpoint"""
mx = (self.x + target.x) / 2
my = (self.y + target.y) / 2
return Point(mx, my)
def cencd(p1,p2,p3):
"""calculating the center of a circle"""
ma=(p2.getY-p1.getY)/(p2.getX-p1.getX)
mb=(p3.getY-p2.getY)/(p3.getX-p2.getX)
hw=p1.halfway(p2)
x=(ma*mb*(p1.getY-p3.getY)+mb*(p1.getX+p2.getX)-ma*(p2.getX+p3.getX))/2*(mb-ma)
ya=-(1/ma)*((x-hw.getX)+hw.getY)
return x,ya
"""defining the points for p1,p2 and p3"""
p = Point(5,5)
q = Point(6,-2)
r=Point(2,-4)
print(cencd(p,q,r))
I get this error message:SyntaxError: duplicate argument 'p1' in function definition on
Traceback (most recent call last):
File "python", line 45, in
File "python", line 34, in cencd
TypeError: unsupported operand type(s) for -: 'method' and 'method'
please assist.
"""working solution """"
ma=(p2.y-p1.y)/(p2.x-p1.x)
mb=(p3.y-p2.y)/(p3.x-p2.x)
hw=p1.halfway(p2)
x1=(ma*mb*(p1.y-p3.y)+mb*(p1.x+p2.x)-ma*(p2.x+p3.x))/(2*(mb-ma))
ya=-(1/ma)*((x1-hw.x))+hw.y
You don't need getters or setters in python nor is it pythonic to use them, you should access the attributes directly:
def cencd(p1, p2, p3):
"""calculating the center of a circle"""
ma = (p2.y - p1.y) / (p2.x - p1.x)
mb = (p3.y - p2.y) / (p3.x - p2.x)
hw = p1.halfway(p2)
x = (ma * mb * (p1.y - p3.y) + mb * (p1.x + p2.x) - ma * (p2.x + p3.x)) / 2 * (mb - ma)
ya = -(1 / ma) * ((x - hw.x) + hw.y)
return x, ya
Both getX and getY are methods in your code, not attributes. So you will need to call them using getX() and getY().
So ma=(p2.getY-p1.getY)/(p2.getX-p1.getX) becomes:
ma = (p2.getY()-p1.getY())/(p2.getX()-p1.getX())
And so on, the other code changes.
Otherwise, you can also define your methods as #property:
class Point:
...
...
#property
def getX(self):
return self.x
#property
def getY(self):
return self.y
...
And now you can access these as p1.getX and p2.getY and so on.
Note that the above #property decorator turns the method into a getter, which makes sense to use only with private variables (variables defined to start with _).
As such, since both x and y are normal attributes of your class, you can access them directly without using and property decorators or using getter methods, like p1.x and p2.y, as #Padraic points in his post.
As Padraic Cunningham said, we don't need getters or setters in Python, but as mu said we can make getters if we want, but normally they are used to get "fake" attributes that are actually computed from true attributes. For example, in the code below I've added a fake norm attribute to your Point class.
I've also added a few more double-underscore methods (aka dunder methods or magic methods) to your class. These methods are discussed in the official Python docs.
One of the most common dunder methods is __repr__() which should return a string that corresponds to how you create an instance of the class. This is especially handy when you're using a class in the interactive interpreter. FWIW, if a class doesn't define a __str__() method its __repr__() method will be used if you attempt to turn a class instance into a string. If a __repr__() method hasn't been defined a default one will be used.
The other dunder methods I've added make it easier to perform arithmetic operations on points; this can make code easier to write and to read. I think you'll agree that it makes the cencd() function a little clearer. (I'm not sure exactly what that function's supposed to do; I assume you've got the algebra correct :) ).
This code was tested on Python 2.6.6; it should run ok on Python 3 without modification.
#!/usr/bin/env python
''' Point class demo
From http://stackoverflow.com/q/28602056/4014959
Written by koseph, Padraic Cunningham, and PM 2Ring
2015.02.19
'''
from __future__ import print_function
from __future__ import division
class Point(object):
def __init__(self, initX, initY):
""" Create a new point at the given coordinates. """
self.x, self.y = initX, initY
#property
def norm(self):
return self.x ** 2 + self.y ** 2
def distance_from_origin(self):
return self.norm ** 0.5
def __repr__(self):
return 'Point({self.x}, {self.y})'.format(self=self)
def __str__(self):
return 'x={self.x}, y={self.y}'.format(self=self)
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __mul__(self, scale):
return Point(self.x * scale, self.y * scale)
__rmul__ = __mul__
def __neg__(self):
return -1 * self
def __sub__(self, other):
return self + -other
def weighted_mean(self, other, weight):
cweight = 1.0 - weight
x = cweight * self.x + weight * other.x
y = cweight * self.y + weight * other.y
return Point(x, y)
def halfway(self, other):
return self.weighted_mean(other, 0.5)
def cencd(p1, p2, p3):
""" Calculate the center of a circle """
a = p2 - p1
b = p3 - p2
ma = a.y / a.x
mb = b.y / b.x
hw = p1.halfway(p2)
x = ma * mb * (p1 - p3).y + mb * (p1 + p2).x - ma * (p2 + p3).x
x /= 2.0 * (mb - ma)
y = -(x - hw.x + hw.y) / ma
return Point(x, y)
p1 = Point(3, 4)
print(p1)
print('p1 is {0!r}, its norm is {1}'.format(p1, p1.norm))
print('and its distance from the origin is', p1.distance_from_origin(), end='\n\n')
p2 = Point(7, 2)
print('p2 is', repr(p2), end='\n\n')
print('p1 + p2 is', repr(p1 + p2))
print('p1 * 0.1 is', repr(p1 * 0.1))
print('p2 - p1 is', repr(p2 - p1), end='\n\n')
p3 = 4 * p1
print('p3 is', repr(p3), end='\n\n')
print('Weighted means from p1 to p3')
for i in range(5):
weight = i / 4.0
print('{0} {1:4.2f} {2!r}'.format(i, weight, p1.weighted_mean(p3, weight)))
print()
print('center of a circle for p1, p2, & p3:', repr(cencd(p1, p2, p3)))
output
x=3, y=4
p1 is Point(3, 4), its norm is 25
and its distance from the origin is 5.0
p2 is Point(7, 2)
p1 + p2 is Point(10, 6)
p1 * 0.1 is Point(0.3, 0.4)
p2 - p1 is Point(4, -2)
p3 is Point(12, 16)
Weighted means from p1 to p3
0 0.00 Point(3.0, 4.0)
1 0.25 Point(5.25, 7.0)
2 0.50 Point(7.5, 10.0)
3 0.75 Point(9.75, 13.0)
4 1.00 Point(12.0, 16.0)
center of a circle for p1, p2, & p3: Point(8.22727272727, 12.4545454545)