# Is there a way to make $g$ changeable independently of $f$ in this code?

My problem is that in the below code, every time I want to change $g$ I also have to change $f$.

Let's say we have three functions: $f$, $h$, and $g$ ($h$ is not really relevant for the question, but its there).

Now let's say that we don't specify what $g$ is yet, because we don't want to restrict it to one particular form. But we define $f$ as follows:

f[x_]:=h[x]+NIntegrate[g[y],{y,0,x}]


Now let's say we want to plot $f[5]$ as a function of a parameterization of $g$:

g[y_]:=a*y^b
(*I am tempted to write the following:*)
Plot3D[f[5],{a,0,1},{b,0,1}]


But the above code obviously doesn't do anything. In order for the approach to work, we would have to instead define

f[x_,a_,b_]:=h[x]+NIntegrate[g[y,a,b],{y,0,x}]
g[y_,a_,b_]:=a*y^b
Plot3D[f[5,a,b],{a,0,1},{b,0,1}]


There are two problems with this approach:

1. It is kind of clumsy

2. It is not versatile. If we want a specification of $g$ that has 3 parameters, then we need to redefine $f$ as well.

3. If we have higher levels of nesting of functions, this becomes even more of a hassle.

Is there a way to do this in a cleaner way without passing parameters from function to function, or at least in a way that if we want to change the parameter specification of $g$, we don't have to change all the others as well?

Is there a Canonical way to do this?

• You could use g and h also as arguments to f... Jan 17, 2018 at 11:21
• This answer for a question about using global variables has several suggestions to achieve the versatility OP wants. Jan 17, 2018 at 12:41
• Also look here where SubValues are used. Can't find SubValues in Help though.
– Hugh
Jan 17, 2018 at 15:17
• @HenrikSchumacher, could you point me to something on how to do that? Jan 17, 2018 at 19:05

Whenever I see an equation with an integral, I always think about trying to convert it into an ODE. Your question falls into this category. So, let's differentiate your equation:

eqn = f[x] == h[x] + Inactive[NIntegrate][g[y], {y, 0, x}];
D[eqn, x]


f'[x] == g[x] + h'[x]

Now, let's solve this ODE and plot the solution:

g[x_] := a x^b
h[x_] := x^2

f = ParametricNDSolveValue[
{u'[x] == h'[x] + g[x], u[0] == h[0]},
u[5],
{x, 0, 5},
{a, b}
];

Plot3D[f[a, b], {a, 0, 1}, {b, 0, 1}]


You can include g in the definition of f as follows:

f[g_, p_] := ParametricNDSolveValue[
{u'[x] == h'[x] + g, u[0] == h[0]},
u[5],
{x, 0, 5},
p
]


Then, we can use different g functions:

f1 = f[a x^b, {a, b}];

Plot3D[f1[a, b], {a, 0, 1}, {b, 0, 1}]


f2 = f[a Cos[b x], {a, b}];

Plot3D[f2[a, b], {a, 0, 1}, {b, 0, 1}]


• what is the name of the technique you use in the end, when you define f2 not as a function, and then later treating it as a function? (so I can look it up in the references of the mathematica language) Jan 17, 2018 at 18:25
• @Programmer2134 ParametricNDSolveValue returns a ParametricFunction object. If pf is a ParametricFunction object, than pf[parameters..] evaluates to a number in this case, but more typical is that it evaluates to an InterpolatingFunction object. So, f[..] returns a ParametricFunction object, and then the Plot3D function evaluates the ParametricFunction object with a and b values. Jan 17, 2018 at 18:45

There are probably half a dozen ways to do what OP wants. Below are given two relatively simple ones.

## args___

I would say the simplest way is to have arbitrary arguments passed from f to g.

ClearAll[f, g, h]
h[x_] := x^2
f[x_, args___] := h[x] + NIntegrate[g[y, args], {y, 0, x}]


Using f with a definition of g:

g[y_, a_, b_] := a*y^b
f[6, 0, 1]

(* 36. )


Using f with another definition of g:

g[y_, a_, b_, c_, d_] := a + b*y + c*y^2 + d*y^3
f[6, 1, 2, 3, 4]

(* 1590. *)


A version of this approach is to use OptionsPattern; another version is to use Association. (For the latter see this answer.)

## Using SubValues

Here the definition of f takes the functions h and g as arguments (instead of the parameters of g as done above.)

ClearAll[f, g, g1, g2, h]
f[h_, g_][x_?NumberQ] := h[x] + NIntegrate[g[y], {y, 0, x}]
h[x_] := x^2


Here is a couple of definitions of g:

g1[y_, a_, b_] := a*y^b

g2[y_, a_, b_, c_, d_] := a + b*y + c*y^2 + d*y^3


Here is how we invoke them:

f[h, g1[#, 0, 1] &][6]

(* 36. *)

f[h, g2[#, 1, 2, 3, 4] &][6]

(* 1590. *)


The convenience of this approach is that we can specify g "on the spot." For example,

f[h, (#^2 + 3*#) &][6]

(* 162. *)


Note that with the approach in the previous section we do enforce the use of a definition of g (which might be desired in some cases.)

• Thank you. Couple of questions: 1. What does the "?" do in "?NumberQ"? 2. why do you use f[..][..] (i.e. 2 sets of brackets instead of 1: f[...])? Is there a name for this? (so I can look it up in the documentation) 3. Is there a way to do it without the "#" (Which I think defines a "pure function")? 4. I cannot find "SubValues" in the documentation. Is there now a new term for it? Jan 19, 2018 at 19:48
• @Programmer2134 1. _?NumberQ is a pattern matching for something that passes the test NumberQ. 2. For clarity. You can use single [] if your prefer. See "tutorial/TheRepresentationOfDerivatives" in the documentation. 3. Why? If # bothers you use args___; or just define g3[x_]:=g2[x,1,2,3,4] and then pass g3. 4. It was given a reference to SubValues in another comment. Jan 20, 2018 at 11:49