Skip to content

Commit

Permalink
fixed bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
xan3c committed Apr 1, 2023
1 parent 0a7b525 commit 669bc15
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 44 deletions.
33 changes: 19 additions & 14 deletions tests/test_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def runTest(self):
self.assertEqual(curve.value(1), [1,1], 'incorrect evaluation')

# Tests curve addition
second_curve = vc.Curve([1, 3], [lambda x: 1, lambda x: 2*x - 1])
second_curve = vc.Curve([1, 3], [lambda x: 1, lambda x: 2 * x - 1])
curve += second_curve

# Tests curve addition applied correctly
Expand All @@ -27,38 +27,43 @@ def runTest(self):
class TestCurveFuncs(unittest.TestCase):
def runTest(self):
# Tests a known scalar integral to 3 decimal places
# See Paul's Online Notes - Line Integrals - Part I Example 3 for analytic solution
# https://tutorial.math.lamar.edu/Classes/CalcIII/LineIntegralsPtI.aspx
curve = vc.Curve([0, 1], [lambda x: 3*x -2, lambda x: 3*x-1 ])
integral = vc.scalar_integrate(curve, lambda x, y: 4*x**3, neval = 1000)
# See Paul's Online Notes - Line Integrals - Part I Example 3 for
# analytic solution
# https://tutorial.math.lamar.edu/Classes/CalcIII/LineIntegralsPtI.aspx
curve = vc.Curve([0, 1], [lambda x: 3 * x - 2, lambda x: 3 * x - 1])
integral = vc.scalar_integrate(curve, lambda x, y: 4 * x ** 3, neval = 1000)
analytic_value = -15 * math.sqrt(2)
decimal_place = 3
self.assertAlmostEqual(integral, analytic_value, decimal_place, 'incorrect scalar integral')

# Tests a known vector function integral to 3 decimal places
# See Paul's Online Notes - Line Integrals Of Vector Fields Example 1 for analytic solution
# See Paul's Online Notes - Line Integrals Of Vector Fields Example 1
# for analytic solution
# https://tutorial.math.lamar.edu/Classes/CalcIII/LineIntegralsVectorFields.aspx
curve = vc.Curve([0, 1], [lambda x: x, lambda x: x**2, lambda x: x**3])
integral = vc.vector_integrate(curve, [lambda x, y, z : 8*x**2*y*z, lambda x, y, z : 5*z, lambda x, y, z : -4*x*y])
curve = vc.Curve([0, 1], [lambda x: x, lambda x: x ** 2, lambda x: x ** 3])
integral = vc.vector_integrate(curve, [lambda x, y, z : 8 * x ** 2 * y * z, lambda x, y, z : 5 * z, lambda x, y, z : -4 * x * y])
analytic_value = 1.000
decimal_place = 3
self.assertAlmostEqual(integral, analytic_value, decimal_place, msg='incorrect vector integral')

# Tests curve_length() of a curve with known length to 3 decimal places
# Namely, the curve is a graph of a line and we find the arc length of this graph
# See Paul's Online Notes - Section 8.1 : Arc Length Example 2 for analytic solution
# Namely, the curve is a graph of a line and we find the arc length of
# this graph
# See Paul's Online Notes - Section 8.1 : Arc Length Example 2 for
# analytic solution
# https://tutorial.math.lamar.edu/classes/calcii/arclength.aspx
curve = vc.Curve([1, 4], [lambda x: x, lambda x: 2 / 3 * (x - 1)**(3/2)])
curve = vc.Curve([1, 4], [lambda x: x, lambda x: 2 / 3 * (x - 1) ** (3 / 2)])
length = vc.curve_length(curve, neval=1000)
analytic_value = 14 / 3
decimal_place = 3
self.assertAlmostEqual(length, analytic_value, decimal_place, 'incorrect length')

# Tests vector_integrate_square() to a known analytic value within 3 decimal places
func = [lambda x, y: -y*x**2, lambda x, y: x*y**2]
# Tests vector_integrate_square() to a known analytic value within 3
# decimal places
func = [lambda x, y: -y * x ** 2, lambda x, y: x * y ** 2]
analytic_value = 224 / 3
integral = vc.vector_integrate_square(func, [2, 2], [4, 4])
self.assertAlmostEqual(integral, analytic_value, decimal_place, 'incorrect square integral')

if __name__ == "__main__":
unittest.main()
unittest.main()
62 changes: 32 additions & 30 deletions vectorcalc/curves.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ class Curve():
"""
Defines a curve that goes from R to R^M
...
-----Attributes-----
begin_point : float
the beginning point of the curve's domain (inclusive)
Expand Down Expand Up @@ -43,14 +41,15 @@ def __init__(self, domain_interval:list, curve_func:list) -> None:
#Defining instance variables

# A dictionary to store where all the breaks in the domain are at.
# This will be useful when we add curves together, so we know when our curve_func parametrization changes
# This will be useful when we add curves together, so we know when our
# curve_func parametrization changes
self.breaks = {}
self.breaks[domain_interval[0]] = curve_func #The start of the domain maps to curve_func
self.breaks[domain_interval[1]] = curve_func

# The domain of the curve
self.begin_point = list(self.breaks)[0]
self.end_point = list(self.breaks)[-1]
self.end_point = list(self.breaks)[-1]
self.dim = len(curve_func) # The dimension of the vector space of the curve

return None
Expand Down Expand Up @@ -113,15 +112,15 @@ def domain_truncate(point_one: float, point_two: float, trunc: int) -> "two floa
truncation_error = []
if a != 0:
truncation_error.append(abs(a - point_one) / a)
if b!= 0:
if b != 0:
truncation_error.append(abs(b - point_two) / b)
for i in truncation_error:
if i > 0.01:
warnings.warn("The relative error of truncating the curve bounds is more than 1%. Consider increasing truncation")

return a, b

def scalar_integrate(curve : Curve, func, neval=100, trunc=10) -> float:
def scalar_integrate(curve: Curve, func, neval=100, trunc=10) -> float:
"""
Finds a numerical integral of a scalar function over a curve via. midpoint method
Expand Down Expand Up @@ -152,20 +151,22 @@ def scalar_integrate(curve : Curve, func, neval=100, trunc=10) -> float:

# Calculates the step_size
domain_range = b - a
step_size = domain_range/neval
step_size = truncate(domain_range / neval, 14)

# Begins calculation of the integral
result = 0
for i in range(neval):
# Finds length between the two curve points
distance = math.dist(curve.value(a + (i+1)*step_size), curve.value(a + i*step_size))
# Finds the evaluation point: the point that lies in the middle of the two curve points
eval_point = curve.value(a + step_size/2 + i * step_size)
# Multiplies the length of the curve with the function evaluated at the evaluation point and adds it to the result
distance = math.dist(curve.value(a + (i + 1) * step_size), curve.value(a + i * step_size))
# Finds the evaluation point: the point that lies in the middle of the
# two curve points
eval_point = curve.value(a + step_size / 2 + i * step_size)
# Multiplies the length of the curve with the function evaluated at the
# evaluation point and adds it to the result
result += func(*eval_point) * distance
return result

def vector_integrate(curve: Curve, func : list, neval=100, trunc=10) -> float:
def vector_integrate(curve: Curve, func: list, neval=100, trunc=10) -> float:
"""
Finds a numerical integral of a vector-valued function over a curve via. midpoint method
Expand Down Expand Up @@ -194,31 +195,35 @@ def vector_integrate(curve: Curve, func : list, neval=100, trunc=10) -> float:
Implement and return error estimation
"""

# Tests that the vector function is in the same space as the curve, so that the dot product is well-defined
# Tests that the vector function is in the same space as the curve, so that
# the dot product is well-defined
if not curve.dim == len(func):
raise Exception('Vector-valued function must be in the same space as the curve.')

# Truncates the boundary points to deal with irrational numbers.
# Truncates the boundary points to deal with irrational numbers.
a, b = domain_truncate(curve.begin_point, curve.end_point, trunc)

# Sets up domain of integral and the step size
domain_range = b - a
step_size = domain_range/neval
step_size = truncate(domain_range / neval, 14)

# Performing the integral
result = 0
for i in range(neval):
# Finds the evaluation point: the point that lies in the middle of two curve points
# Finds the evaluation point: the point that lies in the middle of two
# curve points
eval_point = curve.value(a + step_size / 2 + i * step_size)
# Evaluates the function at this evaluation point
func_eval = [i(*eval_point) for i in func]
# Finds the two curve points (i.e. the bounds where the evaluation point lies in the middle)
begin_bound = curve.value(a + i*step_size)
end_bound = curve.value(a + (i+1)*step_size)
# Finds the two curve points (i.e. the bounds where the evaluation
# point lies in the middle)
begin_bound = curve.value(a + i * step_size)
end_bound = curve.value(a + (i + 1) * step_size)

# In each component multiplies the distance between the bound points and the evaluated point
# In each component multiplies the distance between the bound points
# and the evaluated point
for j, k, l in zip(func_eval, begin_bound, end_bound):
result += j * math.sqrt((l-k)**2)
result += j * math.sqrt((l - k) ** 2)

return result

Expand Down Expand Up @@ -250,7 +255,7 @@ def curve_length(curve: Curve, neval=100, trunc=10) -> float:

return length

def vector_integrate_square(func : list, point_one : list, point_two: list, neval=100, trunc=10) -> float:
def vector_integrate_square(func: list, point_one: list, point_two: list, neval=100, trunc=10) -> float:
"""
Finds a numerical integral of a vector-valued function over a square via. vector_integrate() (using midpoint method)
The square is defined by two points.
Expand Down Expand Up @@ -302,16 +307,13 @@ def vector_integrate_square(func : list, point_one : list, point_two: list, neva
# Creates lines connecting the four points of the square
x_curve_one = Curve([0, 1], [lambda t: side_length * t + x_begin, lambda t : y_begin])
x_curve_two = Curve([0, 1], [lambda t: (x_begin + side_length) - side_length * t, lambda t: y_begin + side_length])
y_curve_one = Curve([0, 1], [lambda t: x_begin + side_length, lambda t: side_length*t + y_begin])
y_curve_one = Curve([0, 1], [lambda t: x_begin + side_length, lambda t: side_length * t + y_begin])
y_curve_two = Curve([0, 1], [lambda t: x_begin, lambda t: (y_begin + side_length) - side_length * t])

# Integrates the function over each line and adds them up
result = (
vector_integrate(x_curve_one, func, neval=neval, trunc=trunc)
+ vector_integrate(y_curve_one, func, neval=neval, trunc=trunc)
# The orientation of the curve is negative here, so we subtract instead of add these two lines
- vector_integrate(x_curve_two, func, neval=neval, trunc=trunc)
- vector_integrate(y_curve_two, func, neval=neval, trunc=trunc)
)
result = (vector_integrate(x_curve_one, func, neval=neval, trunc=trunc) + vector_integrate(y_curve_one, func, neval=neval, trunc=trunc)
# The orientation of the curve is negative here, so we subtract instead
# of add these two lines
- vector_integrate(x_curve_two, func, neval=neval, trunc=trunc) - vector_integrate(y_curve_two, func, neval=neval, trunc=trunc))

return result

0 comments on commit 669bc15

Please sign in to comment.