# Local modification of built-in command via UpValue

I have a computationally intense function f that returns a matrix. Sometimes only the diagonal is needed, which is faster to compute, thus there's a syntax for f to return only the diagonal, say f[...,Diagonal->True]. I would like Diagonal[f[...]] to evaluate to f[...,Diagonal->True].

Naive attempt at using UpValue fails

f[x_] := x.Transpose[x];
Diagonal[f[x_]] ^:= f[x, Diagonal->True];


because f[...] is evaluated first.

How can I achieve the desired behaviour? What would be the "Mathematica way" of handling this situation?

Update:

It appears that the requested behaviour might not be implementable in Mathematica.

Related approaches proposed so far:

• Hold argument to Diagonal: Diagonal[Unevaluated@f[...]] with UpValues f /: Diagonal[f[x_]] := f[x, Diagonal -> True]

Works, but is more cumbersome than directly calling f[..., Diagonal->True] as one needs to remember using Unevaluated instead of an option to f

• Replace Diagonal by a convenience function diagonal, which works with HoldAllComplete

Works, but is more cumbersome than directly calling f[..., Diagonal->True] as one needs to remember using another function diagonal instead of an option to f

• Define only UpValues for f, so it is only evaluated if it has a surrounding context

Works, but requires modifying $Post, which is as undesirable as modifying the built-in Diagonal. • You can use f /: Diagonal[f[x_]] := f[x, Diagonal -> True] but it won't help because in standard evaluation sequence arguments of Diagonal will be evaluated before custom rules. (tutorial/Evaluation). Then you can use Diagonal[Unevaluated@f[{{a, b}, {c, d}}]] but is that handy? – Kuba Jul 13 '16 at 9:27 • @Kuba This would not be handy as it would be easier to call f[..., Diagonal->True] directly. Changing Diagonal via Unprotect to hold its argument is undesirable as well due to affecting other uses of Diagonal. – mrupp Jul 13 '16 at 9:48 • That is what I meant. I'd go with additional diagonalF but maybe I'm missing something. – Kuba Jul 13 '16 at 9:49 ## 2 Answers I know of no method to achieve the specific syntax and evaluation that you want that I would recommend in practice. However for the sake of discussion a way to avoid the unwanted evaluation of the argument is to only define UpValues on f, which only evaluates f[x] when it has some surrounding expression. To get evaluation of a bare input/output we need something like $Post = Identity;. The order of definitions matters here as we need the Diagonal rule to trigger first.

ClearAll[f]

Diagonal[f[x_]] ^:= myFdiagonal[x]

h_[a___, f[x_], b___] ^:= h[a, x.Transpose[x], b]

\$Post = Identity;


Now:

f[{{1}, {3}}]

Diagonal[ f[{{1}, {3}}] ]

{{1, 3}, {3, 9}}

myFdiagonal[{{1}, {3}}]


f[x] should work inside any head that does not have HoldAllComplete and as long as a competing UpValue of a different function does not supersede it.

• It seems even Mathematica itself does not do what I wanted: There is Integrate and NIntegrate, where N[Integrate[...]] appears to not directly translate to NIntegrate, but to first evaluate Integrate and then N. I have accepted your answer for stating that it is likely not possible to do what I wanted. – mrupp Jul 15 '16 at 15:15

I don't think up-values are the way to go. I think you should write a new function, say diag, that has a special behavior for f, but works like Diagonal for any other args. Something like

f[x_] := x.Transpose[x]
f[x_, Diagonal -> True] := Diagonal[x]

SetAttributes[diag, HoldAllComplete]
diag[f[x_]] := f[x, Diagonal -> True]
diag[args___] := Diagonal[args]


Then with

m = {{a, b}, {c, d}};


you would get

f[m]


{{a^2 + b^2, a c + b d}, {a c + b d, c^2 + d^2}}

diag[f[m]]


{a, d}

but

diag[Inverse[m]]


{d/(-b c + a d), a/(-b c + a d)}

I realize this is not so pretty a solution as you hoped for, but I believe it to be the least troublesome.

• This is an option. However, if the user can remember to use diag, then he can remember to use f[..., Diagonal -> True], which overall would be simpler. I was curious whether there is a way to transparently use the efficient solution (f[..., Diagonal->True]) even if the user forgets to explicitly request it and just uses Diagonal[f[...]]. – mrupp Jul 13 '16 at 11:28
• @mrupp. diag is purely a convenience function. Its only purpose is to make code entry easier. I thought that is what you are trying to accomplish. – m_goldberg Jul 13 '16 at 11:30