0

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])]]
Paul R.
  • 877
  • 4
  • 11
  • 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? – Kuba Jan 04 '20 at 07:14
  • 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?) – Paul R. Jan 04 '20 at 11:39

3 Answers3

1

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.

Kuba
  • 136,707
  • 13
  • 279
  • 740
  • 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. – Paul R. Jan 03 '20 at 17:19
  • 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 – Paul R. Jan 03 '20 at 18:24
1

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:

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
0

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.)

Paul R.
  • 877
  • 4
  • 11