2

I need a function fSum that computes the angular sum for some expression, like this:

fSum[3 Sin[2 x], 0, 2 π]

Or from a predefined function, like this:

f[x] = 2 Sin[3 x];

fSum[f, 0, 2 π]

Or plots it like this (exact syntax will probably have to be different here):

Plot[fSum[a Sin[x]], {a, 0, 1}]

I have this stub for fSum:

fSum[expr_, from_ ?NumericQ, to_ ?NumericQ] := Module[{f},
   f = ???? (* How to do this? *)
   Return[NIntegrate[Abs[D[ArcTan[f'[x]], x]], {x, from, to}]];
   ]];

I have asked about something similar before and have then received some helpful answers that solved the particular problem at the time. But now I need to make the fSum function more general so that I also can plot fSum relative to some plot variables in the expression (or function) passed to it. The only thing I can get to work at ???? in the stub is a hardcoded expression, which is very far from what I need. I have searched this forum and have tried many different solutions, but can not make them work in this case. It would be great if the expr parameter can be both an expression, function, and a string containing the inputform text for the expression.

Mikl
  • 101
  • 5
  • 1
    The standard design is to make the independent variable an argument, just like Table, Sum, Integrate, etc. The syntax you're expecting is possible, but personally I don't quite recommend it. See e.g. https://mathematica.stackexchange.com/a/297243/1871 https://mathematica.stackexchange.com/a/127580/1871 – xzczd Mar 23 '24 at 12:11
  • Thanks, I will have close look at it. – Mikl Mar 24 '24 at 08:32

1 Answers1

4
Clear[fSum];

fSum[str_String, rest__] := fSum[ToExpression@str, rest]

fSum[f_, {from_, to_}] := NIntegrate[Abs[D[ArcTan[f'[x]], x]], {x, from, to}];

fSum[expr_, {var_, from_, to_}] := With[{f = Function @@ {var, expr}},
   fSum[f, {from, to}]];

fSum[expr_, from_, to_] := 
 With[{symbol = 
    First@Union@Cases[expr, _Symbol?(Context[#] =!= "System`" &), Infinity]},
  fSum[expr, {symbol, from, to}]]

Usage:

Clear[f, x]
f[x_] = 3 Sin[2 x];

fSum[f, {0, 2 Pi}] (* 11.2452 *)

fSum[3 Sin[2 x], {x, 0, 2 π}] (* 11.2452 *)

fSum[3 Sin[2 x], 0, 2 Pi] (* 11.2452 *)

fSum["f", {0, 2 Pi}] (* 11.2452 *)

fSum["3 Sin[2 x]", {x, 0, 2 Pi}] (* 11.2452 *)

fSum["3 Sin[2 x]", 0, 2 Pi] (* 11.2452 *)

Plot[fSum[a Sin[x], 0, 2 Pi], {a, 0, 1}]

enter image description here

xzczd
  • 65,995
  • 9
  • 163
  • 468
  • Wow, works perfectly and very elegant! Thank you very much xzczd. I will study the last overload carefully, and hopefully I will learn a little about this strange Wolfram language. I have been programming in many different programming languages for more than 40 years now, but never has the learning curve been this steep. – Mikl Mar 24 '24 at 08:29
  • @Mikl If you have difficulty in understanding the code, feel free to continue to ask in the comment :) . – xzczd Mar 24 '24 at 09:01
  • Yeah, can you please explain what is happening in the With[{symbol = ....] in the last overload. Looks very similar to sanskrit to me. – Mikl Mar 24 '24 at 09:14
  • @Mikl In last overload, we're detecting the independent variable automatically. Usually the independent variable in expression is a Symbol that's not in "System\"Context, so we use the patternSymbol?(Context[#] =!= "System`" &)to extract the symbol.?,,&, etc. are just some shorthand, you can check theirFullFormwith e.g.Cases[expr, _Symbol?(Context[#] =!= "System`" &), Infinity] // Hold // FullForm` and check their document by pressing F1. (Actually this isn't necessary, because almost all of the shorthand can be directly found in document by pressing F1. ) – xzczd Mar 24 '24 at 09:26
  • Okay, thank you. I will read up on it. – Mikl Mar 24 '24 at 09:54
  • @Mikl Perhaps this is a bit easier to follow: testfunc = Function[var, Context[var] =!= "System\"]; fSum[expr_, from_, to_] := With[{symbol = First@Union@Cases[expr, PatternTest[_Symbol, testfunc], Infinity]}, fSum[expr, {symbol, from, to}]]` – xzczd Mar 24 '24 at 10:43
  • Thanks xzczd, yes that is a little clearer with the test pattern separated out. Another thing: How would you modify your solution to not compute angular sum, but instead ArcLength with the corresponding range of input parameters? – Mikl Mar 24 '24 at 16:23
  • @Mikl fArc[f_, {from_, to_}] := ArcLength[{x, f[x]}, {x, N@from, to}] (Then replace fSum with fArc in the other 3 definitions, of course. ) – xzczd Mar 25 '24 at 00:36
  • Thanks again xzczd, you are of great help so I can get on with my actual project (which is not about tricking MMA into doing what I naively expect it to). Follow up question: Why N@from but not N@to, and what does it do in this particular case? – Mikl Mar 25 '24 at 08:27
  • @Mikl It's for forcing numeric calculation. (I see you're using NIntegrate in fSum so guess you're looking for numeric result. ) Compare e.g. ArcLength[{Sin[θ], Cos[θ]}, {θ, 0., 2 Pi}] and ArcLength[{Sin[θ], Cos[θ]}, {θ, 0, 2 Pi}]. Alternatively, you can set a WorkingPrecision -> MachinePrecision option to force numeric calculation. – xzczd Mar 25 '24 at 09:50