Message Boards Message Boards


Function in notebook vs function in package?

Posted 4 months ago
5 Replies
3 Total Likes

Hi all,

I started to write a package for my project, where I put all the useful functions and then import the package to use them. Problems arise, so here is the function:

The function is used to generate odes to use in NDSolve

MakeSystem[var_, vart_, sys_]:=
Module[{v, vt, S, St, Sf},
v = var;
vt = vart;
S = sys;
St = S/.Thread[v-> vt]; 
Thread[D[vart, t] == St]]

This is an example to use the function:

dndt = r * (1 - k * n) * n - c * n * p;

dpdt = c * n * p;

var = {n, p};

vart = {n[t], p[t]}

system = {dndt, dpdt};

MakeSystem[var, vart, system]

If I put the function in the notebook, it produces exactly what I want:

n'[t] == r * (1 - k * n[t]) * n[t] - c * n[t] * p[t]

p'[t] == c * n[t] * p[t]

But if I put the function in the package, the D[vart, t] produces zeros, so the output is

0 == r * (1 - k * n[t]) * n[t] - c * n[t] * p[t]

0 == c * n[t] * p[t]

Any help?

POSTED BY: Phuong Nguyen
5 Replies
Posted 3 months ago

Your variable t is the problem. It shows up "raw" in several places. When you put your MakeSystem definition inside of a package, that t will not be in the Global' context, but in whatever context your package uses, so it might be something like Test'Private't (btw, all of the ' should be backticks) You end up producing a derivative of an expression with respect to a variable that isn't in that expression, and such a derivative will evaluate to 0.

One fix would be to ask the caller to provide the symbol, so add a fourth argument to MakeSystem that is expected to be the symbol/variable with respect to which we're going to take the derivative. The problem with this is that you need to make sure you use the same variable in vart, but that's also a good thing, because it makes the intent very explcit.

POSTED BY: Eric Rimbey
Posted 3 months ago

Actually, you could just get rid of vart altogether--it can be constructed from var and the new argument. I would have called the new argument var, but... :)

POSTED BY: Eric Rimbey
Posted 3 months ago

And since I started making refactoring suggestions, I guess I'll continue... You also don't need Module. A couple of simplifications would lead to:

MakeSystem[fnNames_List, var_, rhs_List] :=
  {fns = Through[fnNames[var]]},
  Thread[Equal[D[fns, var], rhs /. Thread[fnNames -> fns]]]]
POSTED BY: Eric Rimbey
Posted 3 months ago

Thanks a lot Eric for the solution.

Yup, that's what I also suspect about the parameter t. I'm just not sure how to handle it.

POSTED BY: Phuong Nguyen
Posted 3 months ago

The code I posted above handles it. I could make it clearer by using pattern matching on var:

MakeSystem[fnNames_List, var_Symbol, rhs_List] := 
 With[{fns = Through[fnNames[var]]}, 
  Thread[Equal[D[fns, var], rhs /. Thread[fnNames -> fns]]]]

Now using your data:

MakeSystem[{n, p}, t, {r*(1 - k*n)*n - c*n*p, c*n*p}]
(*{Derivative[1][n][t] == r n[t] (1 - k n[t]) - c n[t] p[t], Derivative[1][p][t] == c n[t] p[t]} *)
POSTED BY: Eric Rimbey
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
or Discard

Group Abstract Group Abstract