Identify conservative vector fields and understand the condition ∂y∂P=∂x∂Q for path independence
Find potential functions for conservative fields by integrating component functions
Apply the Fundamental Theorem for Line Integrals to evaluate ∫C∇f⋅dr=f(B)−f(A) using only endpoint values
Explain path independence and its connection to conservation laws in physics
Connect these ideas to optimization and understand why gradient descent finds minima regardless of the path taken
Why This Matters: The Fundamental Theorem for Line Integrals is the multivariable generalization of the Fundamental Theorem of Calculus. Just as ∫abf′(x)dx=f(b)−f(a) tells us that the integral of a derivative depends only on boundary values, the line integral theorem tells us that the integral of a gradient depends only on endpoints—not on the path between them. This principle underlies conservation of energy in physics and path-independence in optimization.
The Big Picture
In the previous sections, we learned to compute line integrals ∫CF⋅dr by parametrizing the curve C and integrating. This works but raises a natural question: does the answer depend on which path we take between two points?
For most vector fields, yes—different paths give different integrals. But for a special class called conservative vector fields, something remarkable happens: the integral depends only on where you start and where you end, not on how you get there. This is called path independence.
The Central Insight: A vector field F is conservative if and only if it can be written as the gradient of some scalar function: F=∇f. This scalar function f is called the potential function. When such a potential exists, the line integral from A to B along any path is simply f(B)−f(A).
Historical Origins
The connection between path independence and potential functions emerged from the study of gravitational and electrical forces in the 18th and 19th centuries:
Pierre-Simon Laplace (1749-1827) and Joseph-Louis Lagrange (1736-1813) developed the concept of gravitational potential, showing that gravitational force is the negative gradient of a potential energy function
George Green (1793-1841) introduced the term "potential" and developed Green's theorem, which connects line integrals to area integrals
Lord Kelvin (William Thomson, 1824-1907) applied potential theory to electrostatics and thermodynamics, showing how path independence leads to conservation laws
The physical insight was profound: when lifting a rock from one height to another, the work done depends only on the height difference—not on whether you lift it straight up, carry it diagonally, or take a winding path. Gravity is a conservative force.
Conservative Vector Fields
Definition and Examples
A vector field F is called conservative (or gradient field) if there exists a scalar function f such that:
F=∇f=(∂x∂f,∂y∂f)
The function f is called the potential function (or scalar potential) of F.
Vector Field F
Conservative?
Potential Function f
(2x,2y)
Yes
f(x,y)=x2+y2
(y,x)
Yes
f(x,y)=xy
(y,−x)
No
None exists
(−y,x)
No
None exists (rotational field)
(2xy,x2)
Yes
f(x,y)=x2y
(excos(y),−exsin(y))
Yes
f(x,y)=excos(y)
Testing for Conservative Fields
How can we tell if a field is conservative without guessing a potential function? For a field F=(P,Q) defined on a simply connected region:
F is conservative⟺∂y∂P=∂x∂Q
Simply Connected: A region is simply connected if it has no "holes." Intuitively, any closed curve in the region can be continuously shrunk to a point without leaving the region. The entire plane is simply connected; the plane minus the origin is not.
Example: Is F=(2xy+3,x2−2y) conservative?
Here P=2xy+3 and Q=x2−2y.
∂y∂P=2x
∂x∂Q=2x
Since ∂y∂P=∂x∂Q, the field is conservative!
The Importance of Simple Connectivity: The field F=(x2+y2−y,x2+y2x) satisfies ∂y∂P=∂x∂Q everywhere it is defined, yet integrating around a circle centered at the origin gives 2π, not zero! The problem is that the field is undefined at the origin, creating a "hole" that breaks simple connectivity.
Potential Functions
Finding Potential Functions
Once we know a field is conservative, how do we find its potential function? The method is systematic:
Example: Find the potential for F=(2xy+3,x2−2y)
Step 1: Integrate P=2xy+3 with respect to x:
f(x,y)=∫(2xy+3)dx=x2y+3x+g(y)
The "constant" of integration g(y) may depend on y.
Step 2: Differentiate with respect to y and set equal to Q:
∂y∂f=x2+g′(y)=x2−2y
Step 3: Solve for g′(y):
g′(y)=−2y⇒g(y)=−y2+C
Result:f(x,y)=x2y+3x−y2+C
Verification: You can always check your answer by computing ∇f and verifying it equals F. Here: ∇f=(2xy+3,x2−2y)=F ✓
Interactive: Potential Function Explorer
Explore different potential functions and see how the gradient field (shown as arrows) relates to the surface. Notice that gradient arrows always point "uphill" on the potential surface:
Loading 3D visualization...
The Fundamental Theorem
Statement of the Theorem
Now we state the central result that connects conservative fields, potential functions, and line integrals:
The Fundamental Theorem for Line Integrals: Let C be a smooth curve given by r(t), a≤t≤b, and let f be a differentiable function whose gradient ∇f is continuous on C. Then:
∫C∇f⋅dr=f(r(b))−f(r(a))=f(B)−f(A)
where A=r(a) is the starting point and B=r(b) is the ending point.
This is the multivariable analog of the Fundamental Theorem of Calculus. Just as ∫abf′(x)dx=f(b)−f(a), the line integral of a gradient depends only on the values at the endpoints.
Proof Sketch
The proof uses the chain rule. If r(t)=(x(t),y(t)), then:
∫C∇f⋅dr=∫ab∇f(r(t))⋅r′(t)dt
By the chain rule, the integrand is exactly:
∇f⋅r′(t)=∂x∂fdtdx+∂y∂fdtdy=dtd[f(r(t))]
So the integral becomes:
∫abdtd[f(r(t))]dt=f(r(b))−f(r(a))
Worked Example: The Easy Way vs The Hard Way
Words are persuasive, but a single example does more than a paragraph of theory. We will compute the same line integral two ways: once by parametrizing the curve and grinding through the integral, once by reading the potential at the endpoints. They must agree, and we will see exactly how much labor the Fundamental Theorem saves.
The setup. Let F(x,y)=(2xy+3,x2−2y). We already showed this field is conservative with potential f(x,y)=x2y+3x−y2. Compute ∫CF⋅dr along the curved path r(t)=(1+t,3t2) for 0≤t≤1.
Notice the endpoints: r(0)=(1,0)=A and r(1)=(2,3)=B.
Expand: step-by-step hand calculation (try it yourself first!)
Method 1 — The hard way (direct parametrization). Substitute the path into the field and integrate.
Velocity vector. Differentiate the path: x(t)=1+t⇒x′(t)=1, and y(t)=3t2⇒y′(t)=6t. So r′(t)=(1,6t).
Field on the path. Substitute x=1+t,y=3t2 into F=(P,Q):
P=2(1+t)(3t2)+3=6t2+6t3+3
Q=(1+t)2−2(3t2)=1+2t+t2−6t2=1+2t−5t2
Dot product. Form F(r(t))⋅r′(t)=P⋅1+Q⋅6t:
(6t2+6t3+3)+6t(1+2t−5t2)=3+6t+18t2−24t3
Sanity check at t=21:3+3+4.5−3=7.5. (You can verify this matches the direct substitution.)
Integrate term-by-term.
∫01(3+6t+18t2−24t3)dt=[3t+3t2+6t3−6t4]01
=3+3+6−6=6
Method 2 — The easy way (Fundamental Theorem). No path, no parametrization, no integration. Just evaluate the potential.
At the endpoint B=(2,3):f(2,3)=(2)2(3)+3(2)−(3)2=12+6−9=9.
At the starting point A=(1,0):f(1,0)=(1)2(0)+3(1)−(0)2=0+3−0=3.
Subtract:∫CF⋅dr=f(B)−f(A)=9−3=6. ✓
Both methods give 6. The hard way required differentiating the path, substituting into the field, expanding a cubic polynomial, and antidifferentiating four terms. The easy way required two evaluations of a polynomial. That is the power of the Fundamental Theorem — and it would have worked for any path from A to B, no matter how twisted, because the field is conservative.
Try this yourself: Replace the curved path with the straight line r(t)=(1+t,3t) and redo the hard way. The integrand becomes a different polynomial, but you will still land on 6. The endpoints did not change, so the answer did not change.
Path Independence
An immediate consequence of the Fundamental Theorem is that line integrals of conservative fields are path-independent. If F=∇f, then ∫CF⋅dr has the same value for any curve C connecting A to B.
This is remarkable: whether you take a straight line, a curved arc, or a winding path, you get the same answer! The work done against a conservative force depends only on position change, not on the path taken.
Interactive: Path Independence Demo
Select different paths between the same endpoints and compare their line integral values. For the conservative field, all paths give the same result. For the non-conservative field, different paths give different values:
Loading visualization...
Closed Curves and Circulation
Another key consequence: for a conservative field, the line integral around any closed curve is zero. If C is a closed curve (starting and ending at the same point A), then:
∮C∇f⋅dr=f(A)−f(A)=0
This gives us an equivalent characterization of conservative fields:
F is conservative⟺∮CF⋅dr=0 for all closed curves C
Physical Interpretation: The quantity ∮CF⋅dr is called the circulation of F around C. Conservative fields have zero circulation around every closed curve—there is no net "swirl" or rotation in the field.
Real-World Applications
Physics: Work and Energy
In physics, when a force F moves an object along a path C, the work done is W=∫CF⋅dr.
For a conservative force (like gravity or an ideal spring):
The force is the negative gradient of potential energy: F=−∇U
Work done: W=−∫C∇U⋅dr=−(U(B)−U(A))=U(A)−U(B)
Work equals the decrease in potential energy—independent of path!
This leads to conservation of mechanical energy: the total E=K+U (kinetic + potential) remains constant for conservative forces.
Machine Learning: Optimization Landscapes
In machine learning, we minimize a loss function L(θ) over parameters θ. The gradient ∇L points toward steeper increase, so we move opposite to it:
θnew=θold−α∇L
The Fundamental Theorem tells us that the "work" done against the gradient field—the change in loss—depends only on where we start and end. The path through parameter space doesn't matter for the total change in L:
∫C∇L⋅dθ=L(θend)−L(θstart)
Why This Matters for Optimization: If the loss function is smooth and well-behaved, the specific optimization path (SGD vs. Adam vs. gradient descent) affects only the speed of convergence, not the ability to reduce the loss. The endpoint matters, not the journey—at least in principle. Real neural network loss landscapes are complex, but this theorem provides foundational intuition.
Interactive: Conservative Field Explorer
Explore different vector fields and compute line integrals between points you choose. Compare the numerical integral with the theoretical value f(B)−f(A) from the potential function:
Loading visualization...
Python Implementation
Here's a complete implementation for testing conservative fields, finding potential differences, and computing line integrals:
Conservative Fields and Line Integrals
🐍python
Explanation(7)
Code(163)
1Imports
Import NumPy for numerical computations and matplotlib for visualization.
4Conservative Field Test
Tests if a 2D field is conservative by checking if ∂P/∂y = ∂Q/∂x, which is equivalent to the curl being zero. This is the necessary condition for a potential function to exist.
30Numerical Potential Difference
Finds the potential difference f(B) - f(A) by computing the line integral along a straight path. For conservative fields, this equals the line integral along ANY path between the points.
61Curved Path Line Integral
Computes line integrals along arbitrary parametric curves using the formula ∫_C F · dr = ∫ F(r(t)) · r'(t) dt. This allows us to test path independence.
94Example Functions
Defines a conservative field F = (2x, 2y) = ∇(x² + y²) with known potential, and a non-conservative field F = (-y, x) with non-zero curl.
105Conservative Field Test
Verifies that F = (2x, 2y) is conservative (curl ≈ 0) and confirms the Fundamental Theorem by showing that the line integral equals the potential difference.
120Non-Conservative Demonstration
Shows that for the non-conservative field F = (-y, x), different paths give different integral values, proving path dependence and confirming the field is not conservative.
156 lines without explanation
1import numpy as np
2import matplotlib.pyplot as plt
3from scipy.integrate import quad_vec
45defis_conservative_2d(P, Q, x, y, h=1e-7):6"""
7 Test if a 2D vector field F = (P, Q) is conservative.
89 For F to be conservative: ∂P/∂y = ∂Q/∂x
1011 This is equivalent to curl(F) = 0 in 2D.
1213 Args:
14 P, Q: Component functions of the vector field
15 x, y: Point to test
16 h: Step size for numerical differentiation
1718 Returns:
19 is_conservative: Boolean
20 curl_value: The curl value (should be ~0 if conservative)
21 """22# Compute ∂P/∂y numerically23 dP_dy =(P(x, y + h)- P(x, y - h))/(2* h)2425# Compute ∂Q/∂x numerically26 dQ_dx =(Q(x + h, y)- Q(x - h, y))/(2* h)2728# Curl in 2D: ∂Q/∂x - ∂P/∂y29 curl = dQ_dx - dP_dy
3031 is_conservative =abs(curl)<1e-532return is_conservative, curl
3334deffind_potential_numerical(F, start, end, num_points=100):35"""
36 Find potential difference using line integral.
3738 For conservative F = ∇f:
39 f(end) - f(start) = ∫_C F · dr
4041 This works because line integrals are path-independent
42 for conservative fields.
4344 Args:
45 F: Vector field function F(x, y) -> (Fx, Fy)
46 start: Starting point (x0, y0)
47 end: Ending point (x1, y1)
48 num_points: Number of points for integration
4950 Returns:
51 potential_difference: f(end) - f(start)
52 """53# Parametrize straight line: r(t) = start + t*(end - start)54 t_values = np.linspace(0,1, num_points)55 dt =1/(num_points -1)5657 integral =058for i inrange(len(t_values)-1):59 t =(t_values[i]+ t_values[i+1])/26061# Position on curve62 x = start[0]+ t *(end[0]- start[0])63 y = start[1]+ t *(end[1]- start[1])6465# Velocity (tangent) vector dr/dt66 dx = end[0]- start[0]67 dy = end[1]- start[1]6869# Vector field at this point70 Fx, Fy = F(x, y)7172# F · dr = F · (dr/dt) dt73 integral +=(Fx * dx + Fy * dy)* dt
7475return integral
7677defline_integral_curved(F, parametric_curve, t_start=0, t_end=1, n=200):78"""
79 Compute line integral along a parametric curve.
8081 ∫_C F · dr = ∫_a^b F(r(t)) · r'(t) dt
8283 Args:
84 F: Vector field F(x, y) -> (Fx, Fy)
85 parametric_curve: Function r(t) -> (x(t), y(t))
86 t_start, t_end: Parameter bounds
87 n: Number of integration points
8889 Returns:
90 integral_value: The line integral
91 """92 dt =(t_end - t_start)/ n
93 integral =09495for i inrange(n):96 t = t_start +(i +0.5)* dt
9798# Position99 x, y = parametric_curve(t)100101# Velocity (numerical derivative)102 h = dt /10103 x1, y1 = parametric_curve(t - h)104 x2, y2 = parametric_curve(t + h)105 dx_dt =(x2 - x1)/(2* h)106 dy_dt =(y2 - y1)/(2* h)107108# Field value109 Fx, Fy = F(x, y)110111# Integrate F · r'(t) dt112 integral +=(Fx * dx_dt + Fy * dy_dt)* dt
113114return integral
115116# Example: Conservative field F = (2x, 2y) = ∇(x² + y²)117defF_conservative(x, y):118return2*x,2*y
119120defpotential_f(x, y):121return x**2+ y**2122123# Example: Non-conservative field F = (-y, x)124defF_non_conservative(x, y):125return-y, x
126127# Test conservative field128print("=== Conservative Field F = (2x, 2y) ===")129is_cons, curl = is_conservative_2d(130lambda x, y:2*x,131lambda x, y:2*y,1321.0,1.0133)134print(f"Is conservative: {is_cons}, curl = {curl:.6f}")135136# Compute potential difference via line integral137start, end =(0,0),(2,3)138integral_value = find_potential_numerical(F_conservative, start, end)139theoretical = potential_f(*end)- potential_f(*start)140print(f"Line integral from {start} to {end}: {integral_value:.4f}")141print(f"Theoretical f(B) - f(A): {theoretical:.4f}")142143# Test non-conservative field144print("\n=== Non-Conservative Field F = (-y, x) ===")145is_cons, curl = is_conservative_2d(146lambda x, y:-y,147lambda x, y: x,1481.0,1.0149)150print(f"Is conservative: {is_cons}, curl = {curl:.6f}")151152# Path 1: Straight line153path1 =lambda t:(2*t,3*t)154integral_straight = line_integral_curved(F_non_conservative, path1)155156# Path 2: Curved path (arc)157path2 =lambda t:(2*t,3*t +2*np.sin(np.pi*t))158integral_curved = line_integral_curved(F_non_conservative, path2)159160print(f"Straight path integral: {integral_straight:.4f}")161print(f"Curved path integral: {integral_curved:.4f}")162print(f"Difference: {abs(integral_straight - integral_curved):.4f}")163print("→ Different values prove the field is NOT conservative!")
PyTorch: Conservative Fields via Autograd
Plain Python made the mechanics concrete. PyTorch makes them automatic. Every conservative field comes from a scalar potential f, and PyTorch's autograd engine is, at its core, a machine for computing gradients of scalars. So we can manufacture a conservative field on demand: write down a potential, and let autograd produce F=∇f for us.
The same machinery that trains neural networks — reverse-mode automatic differentiation — is doing a calculus exercise here. The connection is not metaphorical: gradient descent in optimization is integrating a conservative field (the gradient of the loss), and the Fundamental Theorem is the reason the total descent depends only on the start and end loss values.
What we will show below: compute the line integral three ways — once via FTLI (just evaluate the potential at the endpoints), once along the curved path r(t)=(1+t,3t2), once along the straight line — and watch all three answers land on 6.0.
FTLI in PyTorch: Potential → Field → Line Integral
🐍python
Explanation(26)
Code(67)
1Import PyTorch
PyTorch's headline feature is its autograd engine: every tensor with requires_grad=True remembers the operations performed on it, so we can ask for the gradient of any scalar output with respect to any input. We will use this to manufacture a conservative field directly from a potential — no partial derivatives by hand.
This is the same potential we worked out by hand earlier. We accept a tensor p of shape (..., 2) so the function can be called on a single point ([2.0, 3.0]) or on a batch of points (shape (n, 2)) without modification. The trailing ... in p[..., 0] means 'all leading dimensions, then index 0' — it makes the function batch-friendly.
EXECUTION STATE
p (single) = tensor([1.0, 0.0])
x = 1.0
y = 0.0
f(1, 0) = 1²·0 + 3·1 − 0² = 3.0
12⬇ input: endpoint A = (1, 0)
Start of our line integral. Just a plain tensor — no requires_grad needed yet because we only evaluate f here, we do not differentiate through A.
EXECUTION STATE
A = tensor([1.0, 0.0])
13⬇ input: endpoint B = (2, 3)
The other endpoint. The Fundamental Theorem says the line integral of ∇f along ANY path from A to B equals f(B) − f(A). Whether the path is a straight line, a corkscrew, or a single point oscillating between A and B, the answer is the same number.
EXECUTION STATE
B = tensor([2.0, 3.0])
16📚 FTLI shortcut — the entire theorem in one line
Evaluate the potential at both endpoints and subtract. Notice we never wrote down the field F, never parametrized a curve, never integrated. f(B) = 12 + 6 − 9 = 9 and f(A) = 0 + 3 − 0 = 3, so ftli_value = 6.0. This is what makes FTLI such a powerful labor-saver: the moment you find the potential, the integral is trivial.
EXECUTION STATE
potential(B) = tensor(9.0)
potential(A) = tensor(3.0)
ftli_value = tensor(6.0)
17.item() — extract a Python float from a 0-d tensor
A PyTorch tensor with a single value still prints as 'tensor(6.0)'. .item() unwraps it into the plain Python float 6.0 so we can format it with f-strings. Useful for printing and for unit tests; do NOT use inside training loops because it forces a CPU sync.
20📚 conservative_F — turn a potential into a vector field via autograd
Mathematically, F = ∇f. PyTorch's torch.autograd.grad is literally an automatic gradient calculator — give it a scalar and an input tensor, get back the gradient. So we can construct the conservative field on demand, at any point, without ever writing the partials by hand.
EXECUTION STATE
input p (example) = tensor([1.0, 2.0])
expected output = tensor([7.0, -3.0]) (i.e. (2xy+3, x²−2y) at (1,2))
25.clone().detach().requires_grad_(True)
Three little tricks at once: clone() makes a copy so we do not mutate the caller's tensor; detach() severs any prior autograd history so we start fresh; requires_grad_(True) tells PyTorch to track operations on this tensor so we can ask for its gradient later. The trailing underscore means 'modify in place'.
26Forward pass: compute f(p)
PyTorch silently builds a computational graph during this call. Each operation (squaring, multiplying, adding, subtracting) records itself so that grad can later walk backward through them via the chain rule.
27📚 torch.autograd.grad(val, p) — the heart of autograd
Computes ∂val/∂p using reverse-mode automatic differentiation. The first argument is the scalar output, the second is the tensor we want gradients with respect to. Returns a tuple — [0] picks the first (and only) gradient. This is the same chain-rule machinery that backpropagation uses in neural networks; here it is doing a calculus exercise.
EXECUTION STATE
grad at (1, 2) = tensor([7.0, -3.0]) — matches ∇f = (2xy+3, x²−2y)
31Sanity check the autograd field against the hand-derived F
Always test that autograd agrees with the closed-form gradient on a known point. We chose (1, 2) because the hand math is easy: 2·1·2 + 3 = 7 and 1² − 2·2 = −3. If PyTorch printed anything other than [7., -3.], something is wrong with the potential or the autograd setup.
36n = 500 — discretization resolution
We will approximate the continuous integral ∫_C F·dr by sampling 500 points along the curve and using the trapezoidal rule. More points → more accurate but slower. With smooth fields and curves, 500 is plenty; you would see ~6 decimal places of agreement with the exact answer.
Returns a 1-D tensor of 500 numbers starting at 0.0, ending at 1.0, evenly spaced. So t[0]=0.0, t[1]=0.002004, …, t[499]=1.0. These are the t-values where we sample the path r(t).
EXECUTION STATE
t.shape = torch.Size([500])
t[0] = 0.0
t[-1] = 1.0
38x_curve = 1 + t — x-coordinates of the curved path
PyTorch broadcasts the scalar 1.0 across the tensor t, returning a tensor of the same shape with every element incremented by 1. Element-by-element: 1+0=1, 1+0.002=1.002, …, 1+1=2. So x_curve goes from 1 to 2 along the path.
EXECUTION STATE
x_curve[0] = 1.0
x_curve[-1] = 2.0
39y_curve = 3 t² — quadratic rise in y
Element-wise: 3·0²=0, 3·0.002²≈1.2e-5, …, 3·1²=3. So y_curve goes from 0 to 3, but quadratically — slow at the start, accelerating near the end. This is what makes the path 'curved' rather than a straight line.
We need a tensor of tangent vectors, one per sample. r'(t) = (1, 6t), so the x-component is the constant 1 (a tensor of ones the same shape as t) and the y-component is 6t. torch.stack with dim=-1 joins them along a new last axis, producing shape (500, 2): row i is [1, 6·t[i]].
Same stacking trick, but for the path itself. Row i is the 2-D point (x_curve[i], y_curve[i]). This will feed into conservative_F to evaluate the field at every sample.
EXECUTION STATE
points_curve.shape = torch.Size([500, 2])
points_curve[0] = tensor([1.0, 0.0]) = A
points_curve[-1] = tensor([2.0, 3.0]) = B
46List comprehension over points — sample F along the curve
We call conservative_F once per sampled point and stack the results. The reason for the per-point loop: conservative_F uses .clone().detach().requires_grad_(True), which is a per-tensor operation that does not vectorize for free over an extra leading batch dim. There is a vectorized version using torch.func.grad or vmap, but the loop is clearer for pedagogy.
Element-wise multiply gives a (500, 2) tensor whose rows are (F_x·dx/dt, F_y·dy/dt). Summing along dim=-1 collapses each row to its dot product F · r', leaving a 1-D tensor of length 500 — the integrand sampled at every t.
Approximates ∫₀¹ integrand(t) dt using the trapezoidal rule on irregularly- or regularly-spaced samples. Internally: sum 0.5·(y_i + y_{i+1})·(t_{i+1} − t_i). With n=500 and a smooth integrand we get ~6 decimal places of accuracy.
EXECUTION STATE
integral_curve = tensor(6.0000)
56Now a DIFFERENT path: the straight line from A to B
Same A, same B, but a totally different curve in between: x_line goes 1→2 linearly, y_line goes 0→3 linearly. The Fundamental Theorem guarantees this must give the same answer as the curved path. We will check.
57y_line = 3 t — linear ramp instead of quadratic
Same endpoints as y_curve (0 and 3) but a straight ramp. Notice how a single character change (t → t**2) is the difference between a curved and a straight path. The whole point of the theorem is that this change is invisible to the line integral when the field is conservative.
61drdt_line = (1, 3) — constant tangent
For the straight line r(t)=(1+t, 3t), the tangent r'(t)=(1, 3) is constant — no t dependence at all. Compare to the curved path where r'(t)=(1, 6t) varied with t.
62integral_line — the SAME number, computed a totally different way
If everything works, integral_line ≈ 6.0000 just like integral_curve. Different integrand, different geometry, same answer — that IS path independence, made visible.
EXECUTION STATE
integral_line = tensor(6.0000)
66📚 torch.allclose — numerical equality check with tolerance
Returns True iff every element of the two tensors agree to within atol (absolute tolerance) and rtol (relative tolerance, default 1e-5). We use atol=1e-2 because the trapezoidal rule introduces tiny discretization error. The two integrals will not match to machine precision but they will agree well within a hundredth.
68⬆ return: the three-way agreement IS the Fundamental Theorem
All three numbers — ftli_value, integral_curve, integral_line — equal 6.0 (up to trapezoid error). The first was computed by evaluating a potential at two points. The other two were computed by integrating along two different curves. The fact that they all agree is not a coincidence; it is exactly what the Fundamental Theorem for Line Integrals predicts whenever F = ∇f.
41 lines without explanation
1import torch
23# ── 1. Define the SCALAR potential f(x, y) = x²y + 3x − y² ──────────────4defpotential(p):5"""
6 p has shape (..., 2) with p[..., 0] = x, p[..., 1] = y.
7 Returns a scalar (or tensor of scalars) f(x, y).
8 """9 x, y = p[...,0], p[...,1]10return x**2* y +3*x - y**21112# Endpoints A = (1, 0) and B = (2, 3).13A = torch.tensor([1.0,0.0])14B = torch.tensor([2.0,3.0])1516# ── 2. FTLI — the "easy way" in three lines ─────────────────────────────17ftli_value = potential(B)- potential(A)18print(f"f(B) - f(A) = {ftli_value.item():.4f}")# 6.00001920# ── 3. Build the CONSERVATIVE field F = ∇f using autograd ───────────────21defconservative_F(p):22"""
23 Return the gradient of f at point p. Because F = ∇f, this IS the
24 conservative vector field — no hand-derivation of partials needed.
25 """26 p = p.clone().detach().requires_grad_(True)27 val = potential(p)28 grad = torch.autograd.grad(val, p)[0]29return grad
3031# Sanity check at (1, 2): ∂f/∂x = 2xy+3 = 7, ∂f/∂y = x²−2y = −3.32print("F(1, 2) =", conservative_F(torch.tensor([1.0,2.0])))33# tensor([ 7., -3.])3435# ── 4. Direct line integral along a CURVED path r(t) = (1+t, 3t²) ───────36n =50037t = torch.linspace(0.0,1.0, n)38x_curve =1.0+ t
39y_curve =3.0* t**24041# Tangent r'(t) = (1, 6t).42drdt_curve = torch.stack([torch.ones_like(t),6.0* t], dim=-1)4344# Sample F along the path one point at a time.45points_curve = torch.stack([x_curve, y_curve], dim=-1)46F_curve = torch.stack([conservative_F(p)for p in points_curve])4748# Integrand: F(r(t)) · r'(t)49integrand_curve =(F_curve * drdt_curve).sum(dim=-1)5051# Trapezoidal rule on [0, 1]52integral_curve = torch.trapz(integrand_curve, t)53print(f"Curved path ∫ ∇f·dr = {integral_curve.item():.4f}")# ≈6.00005455# ── 5. Same endpoints, different path: STRAIGHT line r(t) = (1+t, 3t) ───56x_line =1.0+ t
57y_line =3.0* t
58points_line = torch.stack([x_line, y_line], dim=-1)59F_line = torch.stack([conservative_F(p)for p in points_line])60drdt_line = torch.stack([torch.ones_like(t),3.0* torch.ones_like(t)], dim=-1)61integral_line = torch.trapz((F_line * drdt_line).sum(dim=-1), t)62print(f"Straight path ∫ ∇f·dr = {integral_line.item():.4f}")# ≈6.00006364# ── 6. All three numbers must agree — that IS path independence ─────────65print("\nPath independence ✓"if torch.allclose(66 integral_curve, ftli_value, atol=1e-267)else"MISMATCH ✗")
Connection to deep learning. When you train a neural network with gradient descent, the trajectory of parameters in weight space is exactly a path through a vector field — the gradient of the loss. Because that field is the gradient of a scalar (the loss itself), it is conservative by construction. The Fundamental Theorem then tells you that the change in loss between two points in weight space depends only on those two points, not on the optimization path. Different optimizers (SGD, Adam, RMSProp) take different paths but cannot improve beyond what the loss landscape allows.
Common Pitfalls
Pitfall
Issue
Solution
Forgetting simple connectivity
Testing ∂y∂P=∂x∂Q on a non-simply connected domain
Check that the domain has no holes; if it does, the test may fail
Wrong order of subtraction
Computing f(A)−f(B) instead of f(B)−f(A)
Remember: endpoint value minus starting point value
Non-unit vectors
Using direction vectors that aren't normalized
For directional derivatives, normalize; for line integrals, the parametrization handles length
Assuming all fields are conservative
Applying FTLI to non-conservative fields
Always test ∂y∂P=∂x∂Q before assuming path independence
Forgetting the constant
Finding f without the arbitrary constant C
Potential functions are unique only up to a constant; f+C works equally well
Test Your Understanding
Summary
The Fundamental Theorem for Line Integrals is one of the most important results in vector calculus. Here are the key takeaways:
Conservative Fields: A field F is conservative if F=∇f for some potential function f. Test: ∂y∂P=∂x∂Q.
The Fundamental Theorem:∫C∇f⋅dr=f(B)−f(A). The line integral depends only on endpoints, not on the path.
Path Independence: For conservative fields, all paths between two points give the same integral value.
Closed Curves: The circulation around any closed curve is zero for conservative fields.
Physical Meaning: Conservative forces conserve mechanical energy; work done depends only on position change.
Looking Ahead: In the next section, we'll study Green's Theorem, which connects line integrals around closed curves to double integrals over the enclosed region. This provides another way to test whether fields are conservative and leads to powerful computational techniques.