0
$\begingroup$

This is similar to a problem I had earlier.

I have a variable Gj that is related to the nj, for example:

Clear[nj]
Gj = If[nj[1] == 0, 0, nj[1] Log[nj[1]/(nj[1] + nj[2] + nj[3])]]

I would like to have a way of defining a function getGj for a given Gj. For the above example, the function would be defined by:

getGj[{a_,b_,c_}] := If[a == 0, 0,a Log[a/(a+b+c)]]

The closest I have come (thanks, Kuba) is:

Gj := If[nj[[1]]==0,0,nj[[1]] Log[nj[[1]]/(nj[[1]]+nj[[2]]+nj[[3]])]];
Unevaluated[getGj[nj_] := Gj;] /. OwnValues[Gj]

which works well for an input list with numeric values, but

ClearAll[xx,x]
xx=Array[x,3];
getGj[xx]

returns

If[x[1] == 0, 0, 
{x[1],x[2],x[3]}[[1]] Log[{x[1],x[2],x[3]}[[1]]/({x[1],x[2],x[3]}[[1]] + {x[1],x[2],x[3]}[[2]]+{x[1],x[2],x[3]}[[3]])]]

rather than

If[x[1] == 0, 0, x[1] Log[x[1]/(x[1]+x[2]+x[3])]]
$\endgroup$
2
  • $\begingroup$ Restating the question makes answers out of sync which will confuse future readers... About the question, why do you need to have a variable Gj = If[nj[1] == 0, 0, nj[1] Log[nj[1]/(nj[1] + nj[2] + nj[3])]], where does it come from? $\endgroup$
    – Kuba
    Jan 4, 2020 at 7:14
  • $\begingroup$ It comes from a thermodynamics program that I am trying to write, and I need to calculate the product of the concentration nj[1] and the log of the activity which is n[1]/(n[1]+n[2]+n[3]), even when n[1] equals zero, in which case the product is zero. (Should I have started a new question?) $\endgroup$
    – Paul R.
    Jan 4, 2020 at 11:39

3 Answers 3

1
$\begingroup$

The first element from a list is nj[[1]], not nj[1].

Additionally notice that Gj can accidentally evaluate to something you don't expect, here nj[[1]] == 0 will remain and keep If unevaluated but e.g. TrueQ@nj will not wait till you provide a value for nj.

That is why this is not the best way to create functions.

You could do:

ClearAll[getGj, nj, Gj];

Gj := If[ (* := !!!*)
  nj[[1]] == 0, 0, nj[[1]] Log[nj[[1]]/(nj[[1]] + nj[[2]] + nj[[3]])]
];

Unevaluated[getGj[nj_] := Gj;] /. OwnValues[Gj]

getGj[{1, 2, 3}]
-Log[6]

It is hard to suggest something more handy without a broader context of the question.

$\endgroup$
2
  • $\begingroup$ Hello - That works great for numerical values, but I was hoping to also be able to input : xx=Array[x,3];getGj[xx] and obtain If[x[1]==0,0,etc.]. In other words, to have it work for symbolic arrays as well. $\endgroup$
    – Paul R.
    Jan 3, 2020 at 17:19
  • $\begingroup$ The function I am trying to build is getGj[{a_, b_, c_}] := If[a == 0, 0, a Log[a/(a + b + c)]]; but for general Gj as a function of the nj $\endgroup$
    – Paul R.
    Jan 3, 2020 at 18:24
1
$\begingroup$

I may be missing some subtlety in your code, or outright misunderstanding your intent, but this appears to do the same thing more simply:

ClearAll[getGj, nj, Gj, zz, z];

Gj = If[nj[1] == 0, 0, nj[1] Log[nj[1]/(nj[1] + nj[2] + nj[3])]];

getGj[in_] := Block[{nj}, Gj /. nj[i__] :> RuleCondition @ in[[i]] ];

zz = Array[z, 3];
nj[1] = 22;

getGj[zz]
getGj[{1, 2, 3}]
If[z[1] == 0, 0, z[1] Log[z[1]/(z[1] + z[2] + z[3])]]

-Log[6]

Reference:

$\endgroup$
3
  • 1
    $\begingroup$ Another test I use is to set some nj to a numerical value, say nj[1]=22. In the above case, getGj[zz] and getGj[{1,2,3}] do not return the proper value. $\endgroup$
    – Paul R.
    Jan 4, 2020 at 11:32
  • $\begingroup$ PS - I add the nj[1]=22 after the function definition. $\endgroup$
    – Paul R.
    Jan 4, 2020 at 11:43
  • $\begingroup$ @Paul Please see and test the update. $\endgroup$
    – Mr.Wizard
    Jan 4, 2020 at 12:49
0
$\begingroup$

This appears to work:

ClearAll[getGj, nj, Gj, zz, z, a, b, c, x, xx];
Gj = If[nj[1] == 0, 0, nj[1] Log[nj[1]/(nj[1] + nj[2] + nj[3])]];
rul = Table[nj[j] -> Slot[j], {j, 1, 3}]
getGjx = Evaluate[Gj /. rul] &;
xx = Array[x, 3];
getGj[xx_] := Apply[getGjx, xx]
ClearAll[xx]

as a test:

ClearAll[z]
zz = Array[z, 3];
nj[1]=22;
getGj[zz]
getGj[{1, 2, 3}]

yields

If[z[1] == 0, 0, z[1] Log[z[1]/(z[1] + z[2] + z[3])]]
-Log[6]

as hoped for. Any improvements would be welcome.

(P.S. I don't understand why I cant substitute the expression for getGjx into the definition of getGj.)

$\endgroup$

Your Answer

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

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