Skip to main content
Fixed typo
Source Link
Michael E2
  • 244.7k
  • 18
  • 351
  • 774

I'll throw this out as another approach one could take. It perhaps goes a little beyond the OP's particular question, but I ran into the same problem some time ago. I came up with this approach as the easiest thing I could manage. I'm not an expert on Association/Dataset objects, so I present it only as the best thing I've come up with so far.

diffEq[ode$29817]diffEq[ode29817]

{diffEq[ode<span class=$32769], diffEq[ode$32770]}" />

{diffEq[ode<span class=$32769], diffEq[ode$32770]}" />

I'll throw this out as another approach one could take. It perhaps goes a little beyond the OP's particular question, but I ran into the same problem some time ago. I came up with this approach as the easiest thing I could manage. I'm not an expert on Association/Dataset objects, so I present only as the best thing I've come up with so far.

diffEq[ode$29817]

{diffEq[ode<span class=$32769], diffEq[ode$32770]}" />

{diffEq[ode<span class=$32769], diffEq[ode$32770]}" />

I'll throw this out as another approach one could take. It perhaps goes a little beyond the OP's particular question, but I ran into the same problem some time ago. I came up with this approach as the easiest thing I could manage. I'm not an expert on Association/Dataset objects, so I present it only as the best thing I've come up with so far.

diffEq[ode29817]

Source Link
Michael E2
  • 244.7k
  • 18
  • 351
  • 774

Preamble

I'll throw this out as another approach one could take. It perhaps goes a little beyond the OP's particular question, but I ran into the same problem some time ago. I came up with this approach as the easiest thing I could manage. I'm not an expert on Association/Dataset objects, so I present only as the best thing I've come up with so far.

First, let me observe that the reason AssociateTo[] is HoldFirst is so that it can find a symbol representing an association to modify. (To me, this makes things awkward in Mathematica, but I am open to being shown that is a result of my lack of expertise.) Evidently, it will do some parsing of the first argument, which is not documented in the AssociateTo page.

Further, I think a complete example would exhibit what happens to the source associations ode1 etc., namely that ODEs is changed but not ode1. This should make sense, since the references to ode1 and ode2 are lost in the definition of ODEs. However, I either read or misread the question to mean that the modification of ode1 and ode2 was desired, probably because that was the problem was trying to solve for myself.

AssociateTo[ODEs[[1]], "ode" -> sol[[1]]]
ODEs
ode1
(*
  {<|"y" -> y, "x" -> x, "ode" -> y[x] == 999|>,
   <|"ode" -> x + y[x] == 1, "y" -> y, "x" -> x|>}

  {<|"y" -> y, "x" -> x, "ode" -> y[x] == 999|>,
   <|"ode" -> x + y[x] == 1, "y" -> y, "x" -> x|>}

  <|"ode" -> y[x] == 0, "y" -> y, "x" -> x|>
*)

Alternative approach

The idea is to wrap the symbol reference to the association in a container that holds its arguments. This can then be used to define operations on the data structure. The form is diffEq[ode], where ode is a Symbol whose value is an Association consisting of the data for the differential equation. You can then use AssociateTo on ode, if you're careful not to let ode evaluate. Then you can define operations like this:

diffEq[ode_]["solution"] := DSolve[ode["ode"], ode["y"], ode["x"]];

There is a method for creating and updating a diffEq[] called setupDiffEq. One could argue that the method for updating should have its own name. Well, you can easily change it.

My data set could be quite large, since it might save things like the results of NDSolve. It was convenient to format it with a summary form, which I've included. I also threw in checkOpts[] to check to see if the rules are valid for our data structure based on some remarks in the comments.

ClearAll[diffEq];
SetAttributes[diffEq, HoldAll];
diffEq /: MakeBoxes[de : diffEq[asc_], form_] /; AssociationQ[asc] :=
  Module[{above, below, ivars},
   ivars = Lookup[asc, "independentVars", Automatic];
   above = {{BoxForm`SummaryItem[{Lookup[asc, "ode", None]}]}};
   below = {};
   BoxForm`ArrangeSummaryBox[diffEq, de, "ODE", above, below, form]];

(* Check that opts are Options of the symbol sym
 *   Returns { status (T/F), filtered good opts } *)
ClearAll[checkOpts];
SetAttributes[checkOpts, HoldFirst];
checkOpts[code_, sym_Symbol, opts : OptionsPattern[]] := 
  With[{oplist = Flatten@{opts}},
   With[{bad = FilterRules[oplist, Except@Options@sym]},
    If[Length@bad > 0,
     Message[sym::optx, First@bad, HoldForm@code];
     {False, FilterRules[oplist, Options@sym]}
     ,
     {True, oplist}
     ]
    ]];

ClearAll[setupDiffEq];
(* Create a diffEq[] from rules *)
call : setupDiffEq[opts : OptionsPattern[]] := Module[{ode},
   With[{opres = checkOpts[call, setupDiffEq, opts]},
    ( (* TBD: validate/process option values *)
      ode = Association[Last@opres];
      diffEq[ode]
      ) /; First@opres
    ]];
(* Change an existing diffEq[] *)
setupDiffEq::optx = "Unknown diffEq key `1` in `2`.";
Options@setupDiffEq = {"ode", "y", "x"};
call : setupDiffEq[de : diffEq[asc_], opts : OptionsPattern[]] :=
  With[{opres = checkOpts[call, setupDiffEq, opts]},
   (AssociateTo[asc, Last@opres]
    ; de
    ) /; First@opres
   ];

Usage:

ode1data = <|"ode" -> y[x] == 0, "y" -> y, "x" -> x|>;
ode1 = diffEq[ode1data]

diffEq[ode1data]

Or with a Module-generated symbol.

ode1 = setupDiffEq["ode" -> y[x] == 0, "y" -> y, "x" -> x]

diffEq[ode$29817]

setupDiffEq[ode1, "ic" -> y[0] == 1]

setupDiffEq::optx: Unknown diffEq key ic->y[0]==1 in setupDiffEq[diffEq[ODE y[x]==0],ic->y[0]==1].

setupDiffEq[diffEq[ode1], "ic" -> y[0] == 1]
setupDiffEq[ode1, "ode" -> y[x] == 999]

diffEq[ode1]

OP's example

The data can be specified as lists, but I followed the OP's lead. If you prefer working strictly with associations, you could modify the definition of setupDiffEq or add a definition like setupDiffEq[a_?AssociationQ] := setupDiffEq@Normal@a.

ode1data = <|"ode" -> y[x] == 0, "y" -> y, "x" -> x|>;
ode2data = <|"ode" -> y[x] + x == 1, "y" -> y, "x" -> x|>;
ODEs = setupDiffEq /@ Normal@{ode1data, ode2data}

{diffEq[ode<span class=$32769], diffEq[ode$32770]}" />

sol = {y[x] == 19, y[x] == 29};(*new values to update with*)
MapThread[
 setupDiffEq[#2, "ode" -> #1] &, {sol, ODEs}]

{diffEq[ode<span class=$32769], diffEq[ode$32770]}" />