I'm trying to do some very basic differential geometry of space curves. For example, a space curve $\gamma:\mathbb R\to\mathbb R^3$ has unit tangent and normal vectors given by $$t(s)=\frac{\gamma'(s)}{\lVert\gamma'(s)\rVert},\\ n(s)=\frac{t'(s)}{\lVert t'(s)\rVert}.$$ I want to define functions that would compute the tangent and normal vectors of an arbitrary curve at any $s$. I tried it in a higher-order functional style, like in say Haskell:

norm[x_] := Sqrt[x.x]
tangent[γ_] := Function[s, γ'[s]/norm[γ'[s]]]
normal[γ_] := Function[s, tangent[γ]'[s]/norm[tangent[γ]'[s]]]

(I need to define my own norm because Mathematica doesn't like to differentiate Norm.)

Unfortunately, this doesn't work. Let γ[s_] := {Cos[s], Sin[s], 0} be our test curve, a circle. Then normal[γ][1] // N does not return a vector, but instead a bizarre expression involving the dot product of 1. and a vector. I have no idea how to begin figuring out what's going on.

I can do it in a less elegant way as

tangent[γ_, s_] := γ'[s]/norm[γ'[s]]
normal[γ_, s_] := D[tangent[γ, ss], ss]/norm[D[tangent[γ, ss], ss]] /. ss -> s

but this requires the use of a dummy variable and the not-so-pretty D[tangent[γ, ss], ss] construction.

Why does my original implementation not work, and is there a simple way to fix it?

  • 1
    $\begingroup$ Have you taken a look at this mathematica.stackexchange.com/questions/18598/… ? If you put for r[t] a different curve it should work as well. $\endgroup$ – Artes Mar 2 '13 at 23:19
  • $\begingroup$ @Artes: I hadn't seen that before. But I'd rather not redefine tangent and normal for every curve I might be interested in. $\endgroup$ – Rahul Mar 2 '13 at 23:42

Your normal isn't working because the derivative is getting "confused" because of the way that your functions pass parameters:

multiplyBy2[r_] := Function[s, 2 r[s]]
r[s_] := {s^2, s^2}

As demonstrated by evaluating the above, the apostrophe sees that your parameter is r, so it takes the derivative with respect to r. That's how the 1 appears in your expression. Specifically, in your original functions, this 1 (derivative of the vector with respect to itself) appears where we expect a vector still, thus creating the unwanted dot products.

This can be avoided by being more explicit with what we want to derive (note simply taking the derivative with respect to s inside the function won't work as s will be replaced by its value before the derivative is taken, resulting in an error).

Thus, in my approach, I use a "dummy" variable, true, but I think the code still remains fairly concise and avoids ReplaceAll.

norm[x_] := Sqrt[x.x]
tangent[γ_] := Function[s, γ'[s]/norm[γ'[s]]]
normal[γ_] := 
  With[{deriv = Function[x, Evaluate[D[tangent[γ][x], x]]]}, 
    Function[s, deriv[s]/norm[deriv[s]]]
γ[s_] := {Cos[s], Sin[s], 0}
normal[γ][1] // N

Finally, when actually using these function, such as within a manipulate, I strongly recommend that you create an evaluated version of the tangent and normal functions for the specific function that is being looked at, thus avoiding constant and expensive re-derivation. I.e., doing something like this:

solenoid[s_] := {Cos[s], Sin[s], s}
solTan = tangent[solenoid];
solNorm = normal[solenoid];


It has come to my attention that something closer to what OP's code uses is multiplyBy2[r]'[s]. After reviewing the Trace of this expression, it is clear as to why the expression evaluates to a matrix - the ' automatically takes the derivative of the sub-expression in Function:

Function[a, x]' hi
(* hi Function[a, 0] *)

It appears that, completely independent of the parameters of the function, the ' travels to x, yielding Function[a, x'] hi (again, see the Trace). Since x is a symbol with no parameters, x' evaluates to 0.

However, in my example, something even more confusing happens: In the Trace, the following steps occur Function[s$,2 r[s$]]',Function[s$,{2 r'[s$],2 r'[s$]}], from which we can see how a matrix may result. Why this happens, I don't know. This is why we explicitly define what we are deriving with respect to.

  • $\begingroup$ A closer analogue would be multiplyBy2[r]'[s], but that strangely yields a matrix, which is still not what I expected. I guess I see the problem, though I'm still in the dark about why it happens. Should I just avoid using primes on higher-order functions? $\endgroup$ – Rahul Mar 3 '13 at 0:27
  • $\begingroup$ @RahulNarain I took a look at the Trace of the expression in your comment, and, as I have singled out in my answer, for some reason, Mathematica jumps from my specified expression to something completely unexplainable. Yes, I would suggest only using primes on symbols that are defined on a "single level." $\endgroup$ – VF1 Mar 3 '13 at 0:46

As VF1's answer explains, the problem is indeed that the prime behaves strangely in tangent[γ]'. I replaced it with a function

d[f_] := Function[x, Evaluate[D[f[x], x]]]

based on the construction in VF1's answer, and now everything works as expected.

tangent[γ_] := Function[s, d[γ][s]/norm[d[γ][s]]]
normal[γ_] := Function[s, d[tangent[γ]][s]/norm[d[tangent[γ]][s]]]

γ1[s_] := {Cos[s], Sin[s], s} (* a helix! *)
γ2[s_] := {s, s^2, 0}
{normal[γ1][s], normal[γ2][s]} // Simplify[#, Assumptions :> s ∈ Reals] &
(* {{-Cos[s], -Sin[s], 0}, {-((2 s)/Sqrt[1 + 4 s^2]), 1/Sqrt[1 + 4 s^2], 0}} *)
  • $\begingroup$ Probably I should also replace every Function[s, ...] with Function[s, Evaluate[...]] for performance as VF1 suggested. Or would that have any side effects? $\endgroup$ – Rahul Mar 3 '13 at 2:32

Here is a simple fix of the OP's definitions:

norm[x_] := Sqrt[x.x]
tangent[γ_] := Function[s, Evaluate[γ'[s]/norm[γ'[s]]]]
normal[γ_] := Function[s, Evaluate[tangent[γ]'[s]/norm[tangent[γ]'[s]]]]

The evaluation of the bodies will take care of the difficulties of tangent[γ]'[s]. (The evaluation of the body of normal is not necessary, unless you plan to take its derivative.) One gets for example

γ[s_] := {Cos[s], Sin[s], 0};
normal[γ][1] // N
(* -> {-0.540302, -0.841471, 0.} *)

The reason for the trouble in the original definition of tangent is that the (symbolic) derivative of γ'[s]/norm[γ'[s]] is

γ᾽᾽[s]/norm[γ'[s]] - norm'[γ'[s]] γ᾽[s] γ''[x]/norm[γ᾽[s]]^2

You might note that γ[s] is not treated as a vector. More precisely, when the chain rule is applied to the derivative of norm[γ'[s]], γ'[s] is treated as a scalar.

N.B. There is a difference between Norm and the OP's norm. Norm assumes its arguments might be Complex, and uses Abs, which can complicate derivatives. For instance, with Norm in place of norm, normal[γ][1] // N has things like Derivative[1][Abs][0.540302] in the answer.


I'd define one function only, keep the built-in Norm and use pure functions:

derVec[\[Gamma]_] := 
Module[{local}, local = Derivative[1][\[Gamma]];
 Function[x, Evaluate[Simplify[local[x]/Norm[local[x]], Assumptions -> {x \[Element] Reals}

Example :

curve = Function[s, {Cos[s], Sin[s], s}];

{tangent, normal} = Rest@NestList[derVec, curve, 2]
  • $\begingroup$ This computes $\gamma''(s)/\lVert\gamma''(s)\rVert$, which is not the same as the normal. One can see this, for example, on the parabola $(s,s^2,0)$. $\endgroup$ – Rahul Mar 3 '13 at 0:33
  • $\begingroup$ @RahulNarain True, should have thought about it, thanks. Will correct. $\endgroup$ – b.gates.you.know.what Mar 3 '13 at 0:41
  • $\begingroup$ @RahulNarain Done. $\endgroup$ – b.gates.you.know.what Mar 3 '13 at 10:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.