1
$\begingroup$

I have got some formula in Mathematica, then I want to pass value to verify them.

full code

vb[v_, a_] := v - 1/2*Sign[a]*(a*a)/Jm;
vf[v_, a_] := v + 1/2*Sign[a]*(a*a)/Jm;
Sb[v_, a_] := vb[v, a] RealAbs[a]/Jm + 1/6 (a*a*a)/(Jm*Jm);
Sf[v_, a_] := vf[v, a] RealAbs[a]/Jm - 1/6 (a*a*a)/(Jm*Jm);

test1 = vAb < vAf; expr1 = {Vm + Am, "Vm + Am"};
test2 = vEb < vEf; expr2 = {Vm - Am,   "Vm - Am"};

(*verify the above  formulas, Vm  Am Jm as coefficients, (v,a) as \
independent variables*)
(*Block: the names to be global,but values to be local*)
(*With: define constant local variable think of With as a \
generalization of the/.operator *)
ClearAll[TSa]
TSa[A_, E_, v_, cutoff_, S_] := 
 Block[{Vm = 20.0, Am = 10.0, Jm = 30.0, vA = A[[1]], aA = A[[2]], 
   vE = E[[1]], aE = E[[2]], TA = Abs[aA]/Jm, TE = Abs[aE]/Jm, 
   vM = v}, 
  With[{vAb = vb[vA, aA], vAf = vf[vA, aA], vEb = vb[vE, aE], 
    vEf = vf[vE, aE], SAb = Sb[vA, aA], SAf = Sf[vA, aA], 
    SEb = Sb[vE, aE], SEf = Sf[vE, aE]},
   
   Evaluate@{{{"vEb", vEb}, {"vEf", vEf}, {"vAb", vAb}, {"vAf", 
       vAf}, {"SAb", SAb}, {"SEf", SEf}}, 
     SortBy[{{"vEb", vEb}, {"vEf", vEf}, {"vAb", vAb}, {"vAf", 
        vAf}, {"SAb", SAb}, {"SEf", SEf}}, Last],
     Which[(*just one simple example*)
      Evaluate@test1, Evaluate@expr1,
      Evaluate@test2, Evaluate@expr2
      ]
     }
   
   ]
  
  ]



S = 14.880227636588513`;
TSa[{10.0, -5.0}, {18.0, 9.5}, 9.583, False, S]

output

    {{{"vEb", 16.4958}, {"vEf", 19.5042}, {"vAb", 10.4167}, {"vAf", 
   9.58333}, {"SAb", 1.71296}, {"SEf", 6.01755}}, {{"SAb", 
   1.71296}, {"SEf", 6.01755}, {"vAb", 10.4167}, {"vAf", 
   9.58333}, {"vEb", 16.4958}, {"vEf", 19.5042}}, {10., "Vm - Am"}}

enter image description here

The first line is before sorting, after sorting, the second line seems incorrect.

If remove Evaluate@ , it is connect. However, I must add Evaluate@ since there is one Which function following SortBy. With function replace rule does not work in

$\endgroup$
6
  • 2
    $\begingroup$ SortBy is evaluated before the values are plugged in by With. I'm confused why you have evaluate SortBy before there are values. If true, it seems a catch-22. $\endgroup$
    – Goofy
    Nov 22, 2023 at 15:04
  • $\begingroup$ I have no idea about the order. Evaluate@{expr1,expr2} I think expr2 is valuated after expr1, expr1 is correct according the output, so I thought expr2 already has these value. $\endgroup$
    – eason
    Nov 22, 2023 at 15:13
  • 1
    $\begingroup$ You are correct about the order of expr1 and expr2, but Evaluate@{expr1,expr2} is evaluated first in With[settings, Evaluate@{expr1,expr2}] and then With[settings, result] is evaluated, where result represents the expression returned by Evaluate@{expr1,expr2}. The reason expr1 has the right final output is because expr1 evaluates to itself. Try evaluating the SortBy[{...}], Last] expression by itself in its own cell -- the result should correspond to the output you see. $\endgroup$
    – Goofy
    Nov 22, 2023 at 15:20
  • 1
    $\begingroup$ We cannot execute your code because you have not provided all of the required definitions. $\endgroup$
    – Bob Hanlon
    Nov 22, 2023 at 16:19
  • $\begingroup$ @BobHanlon I post full code, thanks. $\endgroup$
    – eason
    Nov 22, 2023 at 17:29

2 Answers 2

2
$\begingroup$

In response to the question about design advice...

Since I don't know the semantics, I'm not sure if what follows is ideal, but hopefully it illustrates some better design choices.

vb[Jm_, {v_, a_}] := v - 1/2*Sign[a]*(a*a)/Jm;
vf[Jm_, {v_, a_}] := v + 1/2*Sign[a]*(a*a)/Jm;
Sb[Jm_, {v_, a_}] :=  vb[Jm, {v, a}] RealAbs[a]/Jm + 1/6 (a*a*a)/(Jm*Jm);
Sf[Jm_, {v_, a_}] := vf[Jm, {v, a}] RealAbs[a]/Jm - 1/6 (a*a*a)/(Jm*Jm);

CheckPair[Jm_, pair : {_, _}] := vb[Jm, pair] < vf[Jm, pair];

TSa[Vm_, Am_, Jm_, A_, E_, v_, cutoff_, S_] :=
  With[
    {results = {{"vEb", vb[Jm, E]}, {"vEf", vf[Jm, E]}, {"vAb", vb[Jm, A]}, {"vAf", vf[Jm, A]}, {"SAb", Sb[Jm, A]}, {"SEf", Sf[Jm, E]}}},
    {results,
     SortBy[results, Last],
     Which[
       CheckPair[Jm, A], {Vm + Am, "Vm + Am"},
       CheckPair[Jm, E], {Vm - Am, "Vm - Am"},
       True, "something went wrong"]}]

some explanation

You had lots of repeats of "formal" symbols (e.g. Jm) in your various functions and expressions, and your intention was to give those symbols a value later to cause your functions to magically evaluate. This style of coding relies on side effects, and it's very difficult to get right and maintain. That's why you had to play games with Module, With, and Evaluate. If those things were true constants, then you can define them "globally" and Protect them so they don't accidentally get overwritten. I'm assuming that they're parameters, not constants, and so we can just make them arguments to the functions. Now often, with parameters, we do want to "push them out of the way" a bit, and in that case we might curry these functions or set default values, but I'll leave that to another discussion.

I also changed the function signatures to work more naturally with pairs, since that's what you pass in to TSa (e.g. A and E).

I notice that v, cutoff, and S aren't actually used in the result, and I would have removed them entirely but I'm assuming that they are used in your actual code and that what you presented here was a simplification.

Further improvements might include generalizing the v* and S* functions and improving how we produce the string labels in the results, but I'd be speculating too much to come up with such suggestions. Also, the names seem completely opaque, so renaming things is another potential improvement.

$\endgroup$
2
$\begingroup$

Just making minimal changes to your TSa function (there are larger design issues here that I'm ignoring):

TSa[A_, E_, v_, cutoff_, S_] :=
  Block[{Vm = 20.0, Am = 10.0, Jm = 30.0},
    With[
      {rules = {vAb -> vb @@ A, vAf -> vf @@ A, vEb -> vb @@ E, vEf -> vf @@ E, SAb -> Sb @@ A, SAf -> Sf @@ A, SEb -> Sb @@ E, SEf -> Sf @@ E}},   
      {{{"vEb", vEb}, {"vEf", vEf}, {"vAb", vAb}, {"vAf", vAf}, {"SAb", SAb}, {"SEf", SEf}} /. rules, 
       SortBy[{{"vEb", vEb}, {"vEf", vEf}, {"vAb", vAb}, {"vAf", vAf}, {"SAb", SAb}, {"SEf", SEf}} /. rules, Last], 
       Which[test1, expr1, test2, expr2] //. rules}]]
$\endgroup$
1
  • $\begingroup$ Could you give me some advice on design issues? I will be thankful $\endgroup$
    – eason
    Nov 23, 2023 at 15:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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