def test_is_close():
''' just to make sure '''
assert isclose(4.5, 4.5)
assert isclose(4.5, 4.499999999999999999)
assert not isclose(4.5, 4.6)
# of course, not comprehesive!
# you need to compute a bunch of evenly spaced numbers from a to b
# kind of like range() but for floating point numbers
# I did it as a separate function so I could test it
python类isclose()的实例源码
def test_sine():
# a sine curve from zero to pi -- should be 2
# with a hundred points, only correct to about 4 figures
assert isclose(trapz(math.sin, 0, math.pi), 2.0, rel_tol=1e-04)
def test_sine2():
# a sine curve from zero to 2pi -- should be 0.0
# need to set an absolute tolerance when comparing to zero
assert isclose(trapz(math.sin, 0, 2*math.pi), 0.0, abs_tol=1e-8)
# test the quadratic function itself
# this is pytest's way to test a bunch of input and output values
# it creates a separate test for each case.
def test_quadratic_trapz_args_kwargs():
"""
Testing if you can pass a combination of positional and keyword arguments
one case: A=2, B=-4, C=3
"""
A, B, C = 2, -4, 3
a, b = -2, 2
assert isclose(trapz(quadratic, a, b, A, B, C=C),
quad_solution(a, b, A, B, C),
rel_tol=1e-3) # not a great tolerance -- maybe should try more samples!
def test_sine_freq_amp():
a = 0
b = 5
omega = 0.5
amp = 10
assert isclose(trapz(sine_freq_amp, a, b, amp=amp, freq=omega),
solution_freq_amp(a, b, amp, omega),
rel_tol=1e-04)
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
"""
Determine whether two floating point numbers are close in value.
rel_tol
maximum difference for being considered "close", relative to the
magnitude of the input values
abs_tol
maximum difference for being considered "close", regardless of the
magnitude of the input values
Return True if a is close in value to b, and False otherwise.
For the values to be considered close, the difference between them
must be smaller than at least one of the tolerances.
-inf, inf and NaN behave similarly to the IEEE 754 Standard. That
is, NaN is not close to anything, even itself. inf and -inf are
only close to themselves.
"""
if rel_tol < 0.0 or abs_tol < 0.0:
raise ValueError('error tolerances must be non-negative')
if a == b: # short-circuit exact equality
return True
if math.isinf(a) or math.isinf(b):
# This includes the case of two infinities of opposite sign, or
# one infinity and one finite number. Two infinities of opposite sign
# would otherwise have an infinite relative tolerance.
return False
diff = abs(b - a)
return (((diff <= abs(rel_tol * b)) and
(diff <= abs(rel_tol * a))) or
(diff <= abs_tol))
def trapz(fun, a, b, tol=1e-4, *args, **kwargs):
"""
Compute the area under the curve defined by
y = fun(x), for x between a and b
:param fun: the function to evaluate
:type fun: a function that takes teh vule to be integrated over as
its first argument. Any arguments can be passed in at the end.
:param a: the start point for the integration
:type a: a numeric value
:param b: the end point for the integration
:type b: a numeric value
:param tol=1e-4: accuracy expected.
any other arguments will be passed through to fun.
"""
# compute the range
# loop to try varying step sizes until desired accuracey is achieved
prev_s = None
n = 2 # start with only two steps
while True: # break out when desired accuracy is reached
vals = frange(a, b, n)
s = sum([fun(x, *args, **kwargs) for x in vals[1:-1]])
s += (fun(a, *args, **kwargs) + fun(b, *args, **kwargs)) / 2
s *= (b-a) / n
if prev_s is not None:
# check if we're close enough
# abs_tol is for comparison to zero
if isclose(s, prev_s, rel_tol=tol, abs_tol=tol):
return s
n *= 2
prev_s = s
# this could be a more sophisticated criterion
if n >= 2**22: # it's not going to work (about half the precision of a double)
raise ValueError("Solution didn't converge")
def equal(a, b):
return math.isclose(a, b, abs_tol=0.001)
def __init__(self,
*,
total,
start = None,
vesting_dates = DEFAULT_VESTING_DATES,
vesting = (0.25, 0.25, 0.25, 0.25)):
"""Create an equity grant description.
TOTAL is the total size, in dollars, of the grant. START is
the date on which it starts; if None, the grant clock starts
on the company start date. VESTING_DATES is a sequence of
(MONTH, DAY) pairs on which equity grants vest --- a grant
that vests quarterly will have a four-element
VESTING_DATES sequence.
VESTING is a sequence of numbers that sum to 1.0. With default
vesting dates, each one represents a year over which the grant vests,
and the value of the number indicates the portion of the grant that
vests in that year.
"""
self.total = typecheck(total, numbers.Real)
self.start = typecheck(start, (date, timedelta, type(None)))
self.vesting_dates = typecheck(vesting_dates, seq_of(pair_of(int)))
self.vesting = typecheck(vesting, seq_of(numbers.Real))
if not math.isclose(sum(vesting), 1.0, rel_tol=1e-5):
raise ValueError("vesting fractions do not sum to 1: %1.5f" % sum(vesting))
def diagonalize_curvature(cls, old_u, old_v, ku, kuv, kv, new_norm):
"""Given a curvature tensor, diagonalize to find principal directions and curvatures."""
# Rotate old coord system to be normal to new.
r_old_u, r_old_v = cls.rotate_coord_sys(old_u, old_v, new_norm)
c = 1
s = 0
tt = 0
if not math.isclose(kuv, 0):
# Jacobi rotation to diagonalize.
h = 0.5 * (kv - ku) / kuv
if h < 0:
tt = 1 / (h - math.sqrt(1 + h*h))
else:
tt = 1 / (h + math.sqrt(1 + h*h))
c = 1 / math.sqrt(1 + tt*tt)
s = tt * c
# Compute principal curvatures.
k1 = ku - tt * kuv
k2 = kv + tt * kuv
# Compute principal directions.
if abs(k1) >= abs(k2):
pdir1 = c * r_old_u - s * r_old_v
else:
k1, k2 = k2, k1 # swap
pdir1 = s * r_old_u + c * r_old_v
pdir2 = np.cross(new_norm, pdir1)
# Return all the things.
return pdir1, pdir2, k1, k2
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
"Return true if numbers a and b are close to each other."
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
# ______________________________________________________________________________
# Misc Functions
# TODO: Use functools.lru_cache memoization decorator
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
"Return true if numbers a and b are close to each other."
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
# ______________________________________________________________________________
# Misc Functions
# TODO: Use functools.lru_cache memoization decorator
def get_document_dimensions(tree, max_area=(11.0, 8.5)):
"""
Return the dimensions of this document in inches as to be plotted. If the
document specifies physical units, they will be converted to inches, and
asserted to be less than the working area of the AxiDraw. If the document
does not specify physical units (e.g. the width and height are in pixels
only) it will be scaled to the working area.
Returns a tuple of (width, height) in inches.
"""
max_width, max_height = max_area
raw_width = tree.get('width')
raw_height = tree.get('height')
if not (raw_width and raw_height):
log.warn("This document does not have width and height attributes. "
"Extracting viewbox dimensions.")
svg_width = svg_height = None
raw_width, raw_height = get_viewbox_dimensions(tree.get('viewBox'))
else:
svg_width = convert_to_inches(raw_width)
svg_height = convert_to_inches(raw_height)
if not (svg_width and svg_height):
log.warn("This document does not specify physical units. "
"Auto-scaling it to fit the drawing area.")
width = parse_pixels(raw_width)
height = parse_pixels(raw_height)
aspect_ratio = width / height
max_ratio = max_width / max_height
if aspect_ratio > max_ratio:
# Wider than working area, constrained by width
scale = max_width / width
else:
# Taller than working area, constrained by height
scale = max_height / height
svg_width = scale * width
svg_height = scale * height
assert svg_width <= max_width or math.isclose(svg_width, max_width), \
"SVG width of %s must be <= %s" % (svg_width, max_width)
assert svg_height <= max_height or math.isclose(svg_height, max_height), \
"SVG height of %s must be <= %s" % (svg_height, max_height)
return svg_width, svg_height
def intersection(L1,L2):
#make sure all lines are on the same z plane
#assert (math.isclose(L1.p0.z, L1.p1.z, abs_tol=0.0001))
#assert (L2.p0.z == L2.p1.z)
#assert (L1.p0.z == L2.p0.z)
x1 = L1.p0.x
y1 = L1.p0.y
x2 = L1.p1.x
y2 = L1.p1.y
x3 = L2.p0.x
y3 = L2.p0.y
x4 = L2.p1.x
y4 = L2.p1.y
xnum = (x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4)
xden = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)
ynum = (x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)
yden = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)
try:
intersect = Point(xnum/xden,ynum/yden,L1.p0.z)
if ((intersect.x >= min(x1,x2)-delta) and (intersect.x <= max(x1,x2)+delta) and
(intersect.y >= min(y1,y2)-delta) and (intersect.y <= max(y1,y2)+delta) and
(intersect.x >= min(x3,x4)-delta) and (intersect.x <= max(x3,x4)+delta) and
(intersect.y >= min(y3,y4)-delta) and (intersect.y <= max(y3,y4)+delta)):
return intersect
else:
return None
# return intersect
except:
return None
#given a list of lines that make a manifold perimeter on a slice,
#and a percentage of space that should be infill,
#returns a list of infill lines (grid pattern) for that slice
#assumes print bed area is a square
def calculate_stationary_points(self):
fp_raw=[]
border=5 #don't check points close to simplex border
delta=1e-12
for x,y in zip(self.trimesh.x[border:-border], self.trimesh.y[border:-border]):
start=self.xy2ba(x,y)
fp_try=np.array([])
sol=scipy.optimize.root(self.f,start,args=(0,),method="hybr")#,xtol=1.49012e-10,maxfev=1000
if sol.success:
fp_try=sol.x
#check if FP is in simplex
if not math.isclose(np.sum(fp_try), 1.,abs_tol=2.e-3):
continue
if not np.all((fp_try>-delta) & (fp_try <1+delta)):#only if fp in simplex
continue
else:
continue
#only add new fixed points to list
if not np.array([np.allclose(fp_try,x,atol=1e-7) for x in fp_raw]).any():
fp_raw.append(fp_try.tolist())
#add fixed points in correct coordinates to fixpoints list
fp_raw=np.array(fp_raw)
if fp_raw.shape[0]>0:
self.fixpoints=self.corners.T.dot(np.array(fp_raw).T).T
else:
self.fixpoints=np.array([])
def getLineEnd(x, yStart, perimeterPoints):
"""accepts:
(x,yStart): position of perimeter point
perimeterPoints: list of perimeter points, used to check which one is immediately below (x,yStart)
returns:
yEnd: when combined into (x,yEnd), it is the coordinates of the point on the perimeter immediately below (x,yStart)
NOTE: yEnd is None if there is no such point
"""
pointsBelow = 0
yEnd = None
for index1 in range(len(perimeterPoints)):
index2 = (index1 + 1)%len(perimeterPoints)
if (x, yStart) == perimeterPoints[index1] \
or (x, yStart) == perimeterPoints[index2]:
continue
x0, x1 = perimeterPoints[index1][0], perimeterPoints[index2][0]
if min(x0, x1)<= x <= max(x0, x1) and x0 != x1:
#print(x0, x1)
y0, y1 = perimeterPoints[index1][1], perimeterPoints[index2][1]
#if math.isclose(x0, x1):
# y = max(y0, y1)
#print(y,"!")
#else:
y = (y1-y0)/(x1-x0) * (x-x0) + y0
if y > yStart and (yEnd == None or y < yEnd):
pointsBelow += 1
yEnd = y
if pointsBelow % 2 == 0: yEnd = None
return yEnd
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
"Return true if numbers a and b are close to each other."
return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
# ______________________________________________________________________________
# Misc Functions
# TODO: Use functools.lru_cache memoization decorator
def value(self):
normal = self.__value - self.zero_value
if self.__value > 0:
normal = normal / (self.VAR_MAX - self.zero_value)
else:
normal = -normal / (self.VAR_MIN - self.zero_value)
if isclose(normal, 0, abs_tol=0.04):
return 0
return normal
def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
def isclose(a, b, rel_tol=1e-09, abs_tol=0):
"""
Python 2 implementation of Python 3.5 math.isclose()
https://hg.python.org/cpython/file/v3.5.2/Modules/mathmodule.c#l1993
"""
# sanity check on the inputs
if rel_tol < 0 or abs_tol < 0:
raise ValueError("tolerances must be non-negative")
# short circuit exact equality -- needed to catch two infinities of
# the same sign. And perhaps speeds things up a bit sometimes.
if a == b:
return True
# This catches the case of two infinities of opposite sign, or
# one infinity and one finite number. Two infinities of opposite
# sign would otherwise have an infinite relative tolerance.
# Two infinities of the same sign are caught by the equality check
# above.
if math.isinf(a) or math.isinf(b):
return False
# Cast to float to allow decimal.Decimal arguments
if not isinstance(a, float):
a = float(a)
if not isinstance(b, float):
b = float(b)
# now do the regular computation
# this is essentially the "weak" test from the Boost library
diff = math.fabs(b - a)
result = ((diff <= math.fabs(rel_tol * a)) or
(diff <= math.fabs(rel_tol * b)) or
(diff <= abs_tol))
return result