# Function definition from a variable (RESTATED)

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 == 0, 0, nj Log[nj/(nj + nj + nj)]]


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[]==0,0,nj[] Log[nj[]/(nj[]+nj[]+nj[])]];
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 == 0, 0,
{x,x,x}[] Log[{x,x,x}[]/({x,x,x}[] + {x,x,x}[]+{x,x,x}[])]]


rather than

If[x == 0, 0, x Log[x/(x+x+x)]]

• 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 == 0, 0, nj Log[nj/(nj + nj + nj)]], where does it come from?
– Kuba
Jan 4 '20 at 7:14
• It comes from a thermodynamics program that I am trying to write, and I need to calculate the product of the concentration nj and the log of the activity which is n/(n+n+n), even when n equals zero, in which case the product is zero. (Should I have started a new question?) Jan 4 '20 at 11:39

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

Additionally notice that Gj can accidentally evaluate to something you don't expect, here nj[] == 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[] == 0, 0, nj[] Log[nj[]/(nj[] + nj[] + nj[])]
];

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

getGj[{1, 2, 3}]

-Log


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

• 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==0,0,etc.]. In other words, to have it work for symbolic arrays as well. Jan 3 '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 Jan 3 '20 at 18:24

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 == 0, 0, nj Log[nj/(nj + nj + nj)]];

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

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

getGj[zz]
getGj[{1, 2, 3}]

If[z == 0, 0, z Log[z/(z + z + z)]]

-Log


Reference:

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

This appears to work:

ClearAll[getGj, nj, Gj, zz, z, a, b, c, x, xx];
Gj = If[nj == 0, 0, nj Log[nj/(nj + nj + nj)]];
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=22;
getGj[zz]
getGj[{1, 2, 3}]


yields

If[z == 0, 0, z Log[z/(z + z + z)]]
-Log


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