def get_minmax_data(self, start=None, end=None): """ return the min and max of x and y for the graph of `self` and the parameter between `start` and `end` INPUT: - ``start,end`` - interval on which we are considering the function. OUTPUT: A dictionary """ x_list = [ numerical_approx(P.x, prec=30) for P in self.representative_points() ] y_list = [ numerical_approx(P.y, prec=30) for P in self.representative_points() ] d = {} d['xmin'] = min(x_list) d['xmax'] = max(x_list) d['ymin'] = min(y_list) d['ymax'] = max(y_list) return d
def are_almost_equal(a, b, epsilon=0.0001): # \brief Says if `a` and `b` are equal up to epsilon aN = numerical_approx(a) bN = numerical_approx(b) if abs(aN - bN) < 0.0001: # epsilon return True return False
def check_too_large(obj,pspict=None): try: bb=obj.bounding_box(pspict) mx=bb.xmin my=bb.ymin Mx=bb.xmax My=bb.ymax except AttributeError: print "Object {0} has no method bounding_box.".format(obj) mx=obj.mx my=obj.my Mx=obj.Mx My=obj.My if pspict: from Exceptions import TooLargeBBException # In some circumstances, the comparison # mx<pspict.mx_acceptable_BB # provokes a MemoryError. n_Mx=numerical_approx(Mx) n_mx=numerical_approx(mx) n_My=numerical_approx(My) n_my=numerical_approx(my) if n_mx<pspict.mx_acceptable_BB : raise TooLargeBBException(obj=obj,faulty="xmin",acceptable=pspict.mx_acceptable_BB,got=n_mx) if n_my<pspict.my_acceptable_BB : raise TooLargeBBException(obj=obj,faulty="ymin",acceptable=pspict.my_acceptable_BB,got=n_my) if n_Mx>pspict.Mx_acceptable_BB : raise TooLargeBBException(obj=obj,faulty="xmax",acceptable=pspict.Mx_acceptable_BB,got=n_Mx) if n_My>pspict.My_acceptable_BB : raise TooLargeBBException(obj=obj,faulty="ymax",acceptable=pspict.My_acceptable_BB,got=n_My)
def equation(self): """ return the equation of the line under the form x + by + c = 0 Coefficients 'b' and 'c' are numerical approximations. See Utilities.Intersection EXAMPLES:: sage: from yanntricks import * sage: Segment(Point(0,0),Point(1,1)).equation x - y == 0 sage: Segment(Point(1,0),Point(0,1)).equation x + y - 1 == 0 """ if self.is_vertical: self.coefs = [1, 0, -self.I.x] if self.is_horizontal: self.coefs = [0, 1, -self.I.y] if not (self.is_vertical or self.is_horizontal): self.coefs = [1, -1/self.slope, self.independent/self.slope] x, y = var('x,y') Ix = numerical_approx(self.I.x) Iy = numerical_approx(self.I.y) Fx = numerical_approx(self.F.x) Fy = numerical_approx(self.F.y) coefs = [numerical_approx(s) for s in self.coefs] return coefs[0]*x+coefs[1]*y+coefs[2] == 0
def assert_almost_equal(e1, e2, epsilon=0.0001, failure_message=""): """ Raise a FailedAssertException if the two expressions 'e1' and 'e2' are not equal up to 'epsilon' First try to use ``` e1.is_almost_equal(e2,epsilon) ``` because some objects in 'yanntricks' have that method. If `e1` has not that method : - assume that `e1` and `e2` are numerical - compute a numerical approximation - fail if the absolute value of the difference is larger than `epsilon` """ if hasattr(e1, 'is_almost_equal'): if not e1.is_almost_equal(e2, epsilon): from yanntricks.testing.unit_tests.Exceptions import FailedAssertException raise FailedAssertException( str(e1) + " is not equal to " + str(e2) + " up to " + str(epsilon)) return True v1 = numerical_approx(e1) v2 = numerical_approx(e2) d = abs(v1 - v2) if not d < epsilon: from yanntricks.testing.unit_tests.Exceptions import FailedAssertException raise FailedAssertException( str(e1) + " is not equal to " + str(e2) + " up to " + str(epsilon))
def ERPMooZibfNOiU(): pspict, fig = SinglePicture("ERPMooZibfNOiU") pspict.dilatation(1) t0 = 40 a = 2.3 b = 1.3 O = Point(0, 0) lp = Segment(O, Circle(O, 5).getPoint(t0)) P = lp.midpoint() fun = lambda t: Point(a * cos(t), b * sin(t)).rotation(t0) + P decal = fun(pi / 2) - P Gamma = NonAnalyticPointParametricCurve(lambda x: fun(x) + decal, 0, 2 * pi) Gamma.parameters.plotpoints = 20 pt = Gamma(3 * pi / 2 - 0.15) xx = pt.x v = AffineVector(P, pt).normalize(2) v.parameters.color = "blue" pspict.DrawGraphs(v) F = v.F Fx = F.x a = 7.73542889062775 * cos(11 / 9 * pi + 1.30951587282752) - 7.55775391156456 * cos( 5 / 18 * pi) + 2.5 * cos(2 / 9 * pi) print(numerical_approx(a)) print(numerical_approx(a, digits=5)) fig.no_figure() fig.conclude() fig.write_the_file()
def distance_sq(P,Q,numerical=False): if not numerical : return (P.x-Q.x)**2+(P.y-Q.y)**2 Px=numerical_approx(P.x) Qx=numerical_approx(Q.x) Qy=numerical_approx(Q.y) Py=numerical_approx(P.y) return (Px-Qx)**2+(Py-Qy)**2
def points_list(self): l = [] import numpy ai = numerical_approx(self.angleI) af = numerical_approx(self.angleF) angles = numpy.linspace(ai, af, self.linear_plotpoints) for a in angles: l.append(self.get_point(a)) return l
def PointToPolaire(P=None,x=None,y=None,origin=None,numerical=True): """ Return the polar coordinates of a point. INPUT: - ``P`` - (default=None) a point - ``x,y`` - (defautl=None) the coordinates of the points EXAMPLES: You can provide a point:: sage: from phystricks import Point sage: from phystricks.SmallComputations import * sage: print PointToPolaire(Point(1,1)) PolarCoordinates, r=sqrt(2),degree=45,radian=1/4*pi or directly the coordinates :: sage: print PointToPolaire(x=1,y=1) PolarCoordinates, r=sqrt(2),degree=45,radian=1/4*pi """ from Numerical import numerical_is_negative if origin: Ox=origin.x Oy=origin.y if not origin: Ox=0 Oy=0 if P: Px=P.x Py=P.y else : Px=x Py=y Qx=Px-Ox Qy=Py-Oy if numerical: Qx=numerical_approx(Qx) Qy=numerical_approx(Qy) r=sqrt( Qx**2+Qy**2 ) if abs(Qx)<0.001: # epsilon if Qy>0: radian=pi/2 else : radian=3*pi/2 else : radian=arctan(Qy/Qx) if Qx<0: if Qy>0: radian=radian+pi if Qy<=0: radian=pi+radian # Only positive values (February 11, 2015) if numerical_is_negative(radian): radian=radian+2*pi return PolarCoordinates(r,value_radian=radian)
def numerical_max(x, y, epsilon=None): # Same as `numerical_min` with ad-hoc changes nx = numerical_approx(x) ny = numerical_approx(y) if epsilon is not None: if abs(nx, ny) > epsilon: raise ValueError return max(nx, ny)
def is_almost_orthogonal(self, other, epsilon=0.001): if self.is_vertical: return other.is_horizontal if self.is_horizontal: return other.is_vertical s_slope = numerical_approx(self.slope) o_slope = numerical_approx(other.slope) if abs(s_slope + 1 / o_slope) < epsilon: return True return False
def test_imaginary_part(z,epsilon=0.0001): """ Return a tuple '(isreal,w)' where 'isreal' is a boolean saying if 'z' is real (in the sense that it is real and does not contain 'I' in its string representation) and 'w' is 'z' when the imaginary part is larger than epsilon and an 'numerical_approx' of 'z' when its imaginary part is smaller than 'epsilon' With the collateral effect that it returns a numerical approximation. """ if is_real(z) and "I" not in str(z): return True,z k=numerical_approx(z) if is_real(k): return True,k if abs( k.imag_part() )<epsilon: return True,numerical_approx( z.real_part() ) print("It seems that an imaginary part is not so small.") return False,z
def psi(x, k, prec): if len(x) == 0 or (x[0]**k) > 10**prec: return sg.Rational(0.0) x_power = x.apply_map(lambda y: y**k) return sg.sum( x_power.apply_map(lambda y: sg.numerical_approx(1 / y, digits=prec)))
def distance_sq(P, Q, numerical=False): """ Return the squared distance between P and Q. @param {bool} `numerical` If True, use numerical approximations and return a numerical approximation. """ if not numerical: return (P.x - Q.x)**2 + (P.y - Q.y)**2 Px = numerical_approx(P.x) Qx = numerical_approx(Q.x) Qy = numerical_approx(Q.y) Py = numerical_approx(P.y) return (Px - Qx)**2 + (Py - Qy)**2
def __init__(self, f, mx, Mx): ObjectGraph.__init__(self, self) self.f = f self.mx = mx self.Mx = Mx self.I = self.get_point(mx) self.F = self.get_point(Mx) self.parameters.plotpoints = 100 from numpy import linspace if self.mx is not None and self.Mx is not None: self.drawpoints = linspace(numerical_approx(self.mx), numerical_approx( self.Mx), self.parameters.plotpoints, endpoint=True) self._curve = None self.mode = None
def LaTeX_lines(self): """ Return the lines to be included in your LaTeX file. """ a = [] a.append(self.comments()) if self.figure_environment: a.append( "The result is on figure \\ref{"+self.name+"}. % From file "+self.script_filename) # The pseudo_caption is changed to the function name later. a.append("\\newcommand{"+self.caption+"}{"+pseudo_caption+"}") a.append("\\input{%s}" % (self.filename.from_main())) else: text = r"""\\begin{center} INCLUSION \end{center}""".replace("INCLUSION", "\\input{%s}" % (self.filename.from_main())) if len(self.record_pspicture) == 1: pspict = self.record_pspicture[0] # By the way, this is a reason why we cannot do this before to have visual_xsize = pspict.visual_xsize() # concluded the picture. text = text.replace("WIDTH", str( numerical_approx(visual_xsize, digits=3))+"cm") a.append(text) text = "\n".join(a) return text
def number_to_string(x,digits): from Numerical import is_almost_zero nx=numerical_approx(x) # Avoid something like "0.125547e-6" (LaTeX will not accept). if is_almost_zero(nx,0.001): if digits==1: return "0" return "0."+"0"*(digits-1) sx=str(nx) # in a definitive release, this test can be removed. # this is only for my culture; I guess that it never happens if "." not in sx: print(x) print(sx) raise sx=sx+"0"*(digits+1) # be sure not to lack digits if nx<0: sx=sx[0:digits+2] # +1 for the decimal dot, +1 for the minus else : sx=sx[0:digits+1] if sx.endswith("."): sx=sx[:-1] return sx
def __call__(self, xe, numerical=False): """ return the value of the function at given point INPUT: - ``xe`` - a number. The point at which we want to evaluate the function - ``numerical`` (boolean, default=False) If True, return a numerical_approximation EXAMPLES:: sage: from yanntricks import * sage: x=var('x') sage: f=phyFunction(cos(x)) sage: f(1) cos(1) sage: f(1,numerical=True) 0.540302305868140 """ if numerical: return numerical_approx(self.sageFast(xe)) else: try: return self.sage(x=xe) except TypeError: # Happens when one has a distribution function try: return self.sage(xe) except TypeError: print("ooMHAQooMbDokI") print(self, type(self)) print(xe, type(xe)) raise
def inner_product(v, w, numerical=False): """ Return the inner product of vectors `v` and `w` @param v a vector @param w a vector @param numerical a boolean If `numerical` is true, the computations are done on numerical approximations of the coordinates. """ if numerical: if not v.I.is_almost_equal(w.I): raise OperationNotPermitedException( "I only compute inner products " "of vectors based on the same point.") if not numerical: if v.I != w.I: raise OperationNotPermitedException( "I only compute inner products " "of vectors based on the same point.") s = v.Dx * w.Dx + v.Dy * w.Dy if numerical: return numerical_approx(s) return s
def __init__(self, a, b): self.x = SR(a) self.y = SR(b) ObjectGraph.__init__(self, self) self.point = self.obj self.add_option("PointSymbol=*") self._advised_mark_angle = None try: ax = abs(numerical_approx(self.x)) if ax < 0.00001 and ax > 0: self.x = 0 ay = abs(numerical_approx(self.y)) if ay < 0.00001 and ay > 0: self.y = 0 except TypeError: pass
def roundingMinMax(d): """ From a dictionary of "xmin,..." return the dictionary of three-digit rounded values """ new = {} for p in ["xmax", "xmin", "ymax", "ymin"]: s = numerical_approx(d[p], digits=3) new[p] = s return new
def extrapolate(matrix, Psi, prec=None): v = Psi[1][-1, :] B = create_B(matrix) a = sum(sum(Psi[1])) b = sum(sum(B*v)) if prec: return sg.numerical_approx(a + b, digits=prec) else: return a + b
def equation(self, numerical=False): """ Return the equation of `self`. OUTPUT: an equation. EXAMPLES:: sage: from yanntricks import * sage: circle=Circle(Point(0,0),1) sage: circle.equation() x^2 + y^2 - 1 == 0 :: sage: circle=CircleOA(Point(-1,-1),Point(0,0)) sage: circle.equation() (x + 1)^2 + (y + 1)^2 - 2 == 0 If 'numerical' is True, return numerical approximations of the coefficients. """ if numerical == True and self._numerical_equation is not None: return self._numerical_equation if numerical == False and self._equation is not None: return self._equation x, y = var('x,y') if not self.visual: cx = self.center.x cy = self.center.y cr = self.radius self._equation = (x - cx)**2 + (y - cy)**2 - cr**2 == 0 if not numerical: return self._equation if numerical: cx = numerical_approx(cx) cy = numerical_approx(cy) cr = numerical_approx(cr) self._numerical_equation = (x - cx)**2 + (y - cy)**2 - cr**2 == 0 return self._numerical_equation Rx = self.radius / self.pspict.xunit Ry = self.radius / self.pspict.yunit if numerical == False: self._equation = (x-self.center.x)**2/Rx**2 + \ (y-self.center.y)**2/Ry**2-1 == 0 return self._equation if numerical == True: Rx = numerical_approx(Rx) Ry = numerical_approx(Ry) cx = numerical_approx(self.center.x) cy = numerical_approx(self.center.y) self._numerical_equation = (x - cx)**2 / Rx**2 + ( y - cy)**2 / Ry**2 - 1 == 0 return self._numerical_equation
def point_to_box_intersection(P,box,pspict=None): from phystricks.src.Utilities import distance_sq A=Point(box.xmin,box.ymin) B=Point(box.xmax,box.ymin) C=Point(box.xmax,box.ymax) D=Point(box.xmin,box.ymax) # n'écrivez pas ça au tableau quand un inspecteur est dans la salle : center=(A+B+C+D)/4 line=Segment(P,center) edges=[Segment(A,B),Segment(B,C),Segment(C,D),Segment(D,A)] inter=[] for ed in edges: c=Intersection(line,ed) if len(c)>0: S=c[0] # We deal with the case in which the line travers the corner. # In this case, the line passes trough the other one. if S==A: inter=[A,C] if S==B: inter=[B,D] if S==C: inter=[A,C] if S==D: inter=[B,D] # The last two tests are to know if S lies between ed.I and ed.F # We use numerical approximations in order to avoid some # OverflowError: Python int too large to convert to C long elif numerical_approx( (S.x-ed.I.x)*(S.x-ed.F.x) )<0: inter.append(S) elif numerical_approx( (S.y-ed.I.y)*(S.y-ed.F.y) )<0: inter.append(S) if len(inter)==2: inter.sort(key=lambda Q:distance_sq(Q,P,numerical=True)) if pspict: for i,S in enumerate(inter): S.put_mark(0.2,angle=None,added_angle=0,text=str(i),pspict=pspict) pspict.DrawGraphs(inter,line,center,box) return inter
def visual_angleIF(self, pspict): from yanntricks.src.point import Point from yanntricks.src.AngleMeasure import AngleMeasure aI1 = visual_polar_coordinates( Point(cos(self.angleI.radian), sin(self.angleI.radian)), pspict).measure aF1 = visual_polar_coordinates( Point(cos(self.angleF.radian), sin(self.angleF.radian)), pspict).measure a = numerical_approx(aI1.degree) b = numerical_approx(aF1.degree) if a > b: a = a - 360 aI2 = AngleMeasure(value_degree=a) else: aI2 = aI1 aF2 = aF1 return aI2, aF2
def numerical_min(x, y, epsilon=None): ## # \brief return the minimum of `x` and `y` # # Compute numerical approximations of `x` and `y` and return the min # # If `epsilon` is given, raise an exception if the difference is # smaller than `epsilon`. # # The reason is that Sage cannot always determine the min or the max of # expressions like ```1000``` of type `int` and ```cos(0.0823552493237255*pi)``` of type `sage.symbolic.expression.Expression` nx = numerical_approx(x) ny = numerical_approx(y) if epsilon is not None: if abs(nx, ny) > epsilon: raise ValueError return min(nx, ny)
def solve_one_var(self, eqs, var): """ Solve the equations with respect to the given variable Returns a list of numerical values. """ liste = solve(eqs, var, explicit_solutions=True) a = [] for soluce in liste: a.append(numerical_approx(soluce.rhs())) return a
def is_almost_equal(self, other, epsilon=0.0001): ## # return true if `self` and `other` have coordinates difference # lower than `epsilon` # from yanntricks.src.NoMathUtilities import logging if not isinstance(other, Point): logging("We are comparing " + type(self) + " with " + type(other) + ". We continue, but this is strange.") sx = numerical_approx(self.x) sy = numerical_approx(self.y) ox = numerical_approx(other.x) oy = numerical_approx(other.y) if abs(sx - ox) > epsilon: return False if abs(sy - oy) > epsilon: return False return True
def length(self): """ return (a numerical approximation of) the length of the segment EXAMPLES:: sage: from phystricks import * sage: Segment(Point(1,1),Point(2,2)).length sqrt(2) """ return numerical_approx(self.exact_length)
def is_almost_orthogonal(self, other, epsilon=0.001): """ Return true is `self` and `other` are orthogonal segments The answer is based on numerical approximations of the slopes. If \f$ k \f$ is the slope of `self`, check if the slope of the other is \f$ -1/k \f$ up to `epsilon`. See `is_orthogonal` """ if self.is_vertical: return other.is_horizontal if self.is_horizontal: return other.is_vertical s_slope = numerical_approx(self.slope) o_slope = numerical_approx(other.slope) if abs(s_slope+1/o_slope) < epsilon: return True return False