Defining functions with special cases

I'm trying to define a function myFunc with a special case:

myFunc[x_, y_] = (x^2 - y) Log[x^2 - y];
myFunc[x_, x_^2] = 0;


This seems to work in limited cases only:

In[1] := myFunc[x, x^2]
Out[1] = 0


But if I put in numbers, or anything else, it fails. How would I fix this?

In[2] := myFunc[2.1, 2.1^2]
Out[2] = Indeterminate

In[3] := myFunc[a^2, a^4]
Out[3] = Indeterminate


I am more interested in making case with numbers to work. What should I do?

-
Patterns are not a good way to define functions with special cases, see my comment and answer below. – Jens Jan 3 '13 at 4:33

You could try:

myFunc[x_, y_] := (x^2 - y) Log[x^2 - y];
myFunc[x_, y_] := 0 /; y == x^2;

{myFunc[2.1, 2.1^2], myFunc[a^2, a^4]}
(*
-> {0,0}
*)

-
+1 This definitely achieves what was asked (even though the example function doesn't really need a case distinction). – Jens Jan 3 '13 at 4:45
Perfect! Upon further usage, I discovered that I should define the special cases before the general function for this to work fool-proof. Can you verify/comment on this? – QuantumDot Jan 3 '13 at 6:18
@QuantumDot Sorry, but I'm not sure about how Mathematica does the prioritization of pattern testing. Perhaps that is a good question ... if it wasn't asked before :) – Dr. belisarius Jan 3 '13 at 7:06

Your problem is not that the function needs to have a special value at a certain point, because the function is in fact continuous at the point you're trying to single out. The only problem is that Mathematica isn't calculating the limit $\lim_{\epsilon\to 0}\epsilon\ln(\epsilon) = 0$ when it should.

Instead of singling out the offending point by pattern matching, I would take the more mathematically motivated route of specifying that a limit exists and should be taken:

Clear[myFunc]
myFunc[x_, y_] := Limit[d Log[d], d -> x^2 - y];
myFunc[4, 4]
(* ==> 12 Log[12] *)
myFunc[4, 16]
(* ==> 0 *)


Now you don't need any case distinctions at all.

Edit

Looking at the other solutions, one thing came to mind that was missing if you do want to make a case distinction (i.e., if you had a different function in your example that requires it):

Clearly you want

myFunc[a^2, a^4] == 0


myFunc[a^2, b^4] /. b -> a


Strictly speaking, all definitions including mine from above make a potential mistake here in assuming that a and b are different when returning a result from myFunc, so that if you subsequently set b -> a you get an error from the $0 \times \ln 0$ expression.

To circumvent that, it might be best to insist on keeping the result of myFunc conditional if it gets symbolic parameters. Then you could instead define it like this:

Clear[myFunc];
myFunc[x_, y_] :=
Piecewise[{{(x^2 - y) Log[x^2 - y], x^2 != y}, {0, True}}];
myFunc[2, 4]
(* ==> 0 *)
myFunc[a^2, a^4]
(* ==> 0 *)
myFunc[a^2, b^4]


$\begin{cases} \left(a^4-b^4\right) \log \left(a^4-b^4\right) & a^4\neq b^4 \\ 0 & \text{True} \end{cases}$

Now the result of the last symbolic input is the unevaluated Piecewise expression, and consequently we can move on without fear, getting the correct result if we later look at the problematic special case:

myFunc[a^2, b^4] /. b -> a
(* ==> 0 *)


Again, in your specific case that's not the best approach because you can use a limiting process to define the function.

-
Your second solution involving Piecewise is particularly useful to me since the problem I have at hand is a function involving 3 argument with lots of different Log's which have many limiting cases. – QuantumDot Jan 3 '13 at 6:29
@QuantumDot If the answer is useful to you ... vote it up :) – Dr. belisarius Jan 3 '13 at 7:07

You can set the function to Hold:

SetAttributes[myFunc, HoldAll];
myFunc[x_, y_] = (x^2 - y) Log[x^2 - y];
myFunc[x_, x_^2] = 0;

myFunc[2.1, 2.1^2]
0


But this is not a "robust" approach without further fiddling. For example:

myFunc[5, (2+3)^2]
Indeterminate

-
This may not be mathematically robust but it is the desired pattern and the way I would approach this myself. +1 – Mr.Wizard Jan 3 '13 at 0:48
This will fail for example for myFunc[Sin[Pi/4], 1/2] – Jens Jan 3 '13 at 4:28