Let's say we have a multivariate piecewise function


Now we want to determine the limit in f(0,0) with the Limit function. From the wolfram doc I can see two possible ways to do so.

Limit[f[x1,x2], {x1,x2}->{0,0}]
Limit[f[x,x], x->0]

While the first expression does not evaluate the limit, the second one gives the expected result 1.

Why does the first expression not work?

  • 1
    $\begingroup$ Related: mathematica.stackexchange.com/a/225100/4999 -- Multivariate limits do not seem to be robust with respect to Piecewise functions yet. Possibly related is that there does not appear to be a way to limit the domain in a multivariate limit (the way you can with Direction). This would be needed to find limits of piecewise functions. $\endgroup$ – Michael E2 Aug 1 '20 at 13:07

My guess is that Limit can have trouble if (x, y} -> {a, b} where {a, b} is not an interior point of the domain. For instance, I would say the limit here is well-defined since {0, 0} is a limit point of the domain and that the limit is 1:

Limit[ConditionalExpression[Sin[x1]/x1, x1 > x2], {x1, x2} -> {0, 0}]
(*  Indeterminate  *)

Limit can handle some piecewise functions:

  { Sin[1/x1] / x1, x1 > x2}, (* <-- N.B. *)
  {Sin[x2]/x2, x1 <= x2}}],
 {x1, x2} -> {0, 0}]

(*  Indeterminate  *)

So it seems to be a question of robustness.

An alternative when Limit fails is to try to find the limit of each of the separate pieces without the restriction on the domain of the piece. If they each exist and are equal, we can say the limit is the limit of the pieces. If some exist and are not all equal, then the limit does not exist. Otherwise, I think we can't be sure. The following is adapted from this answer of mine.

pwLimit::DNE = 
  "The limit of at least one of the pieces does not exist as ``.";
pwLimit::nopcs = "Could not solve for the pieces.";
pwLimit[f_, spec_, opts : OptionsPattern[Limit]] := 
  Module[{f0, jac0, pcs = {}, z, res}, 
   pcs = Replace[ (* Solve[..,Reals] separates PW fn *)
     z /. Solve[z == f, z, Reals],
     {ConditionalExpression[y_, _] :> y},
    res = Limit[#, spec, opts] & /@ pcs,
    res = $Failed];
   res = Replace[res, {
      uneval_ /;  (* Limit did not find limit *)
         ! FreeQ[uneval, Limit] :>
      lim_ /;  (* all limits equal *)
         Equal @@ lim :> 
      lim_ /;  (* limits exist/infinite but different *)
          NumericQ[#] || MatchQ[#, Infinity | -Infinity | ComplexInfinity] &
          ] :> 
      lim_ :>  (* at least two limits exist and differ *)
        With[{nums = 
          Cases[lim, _?NumericQ | Infinity | -Infinity | ComplexInfinity]},
         Indeterminate /; Length@Union[nums, SameTest -> Equal] > 1
      i_ /;  (* limit(s) DNE on whole domain but might on piece *)
         ! FreeQ[i, Indeterminate] :> (
       Message[pwLimit::DNE, spec]
   res /; FreeQ[res, $Failed]];

It is called like Limit. It might make sense to call it after Limit fails:

  Piecewise[{{Sin[x1]/x1, x1 > x2}, {Sin[x2]/x2, x1 <= x2}}],
  {x1, x2} -> {0, 0}] /.
 Limit -> pwLimit

(*  1  *)

If you'd prefer that a failed call stay as Limit[..] instead of pwLimit[..]], then the following will make the replacement only if pwLimit is successful.

  Piecewise[{{Sin[x1]/x1, x1 > x2}, {Sin[x2]/x2, x1 <= x2}}],
  {x1, x2} -> {0, 0}] /. 
 HoldPattern[Limit[args__]] :> 
  With[{res = pwLimit[args]}, res /; FreeQ[res, pwLimit]]

(*  1  *)
  • 1
    $\begingroup$ Probably don't need third case (condition VectorQ[..]) as it would handled by the fourth case. $\endgroup$ – Michael E2 Aug 1 '20 at 14:52
  • $\begingroup$ That solved the problem, thanks Michael! $\endgroup$ – Alex Mahone Aug 1 '20 at 18:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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