5
$\begingroup$

I came across this post, here I change the last line of the code

Unprotect[Sqrt];
Sqrt[x_] = "blahblah";
Protect[Sqrt];
Sqrt[2]

"blahblah"

Unprotect[Sqrt];
ClearAll[Sqrt];
Protect[Sqrt];
Sqrt[{1, 2, 3}]

{1, Sqrt[2], Sqrt[3]}

And I do the same for Log

Unprotect[Log];
Log[x_] = "blahblah";
Protect[Log];
Log[2]

"blahblah"

Unprotect[Log];
ClearAll[Log];
Protect[Log];
Log[{1, 2}]

Log[{1, 2}]

Since I've ClearAll the definitions and attributes of Sqrt and Log, and neither of them have Listable attributes.

Attributes[{Sqrt, Log}]

{{Protected}, {Protected}}

So why is Sqrt still Listable while Log is not? Do I misunderstand something?

$\endgroup$
0

1 Answer 1

6
$\begingroup$

Leaving aside the wisdom of modifying System functions this is an interesting question.

I would not have been surprised to see this behavior had the input list been packed as I have already learned about low-level optimizations on packed arrays. See:

However that does not appear to be the issue here since (typed in) {1, 2, 3} is not packed. Apparently the "listable" behavior of Sqrt is not (only) implemented in terms of the attribute Listable. As an example here is function without Listable that still threads over lists:

f[x_List] := f /@ x

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

Leonid writes about Listability here:

Quoting:

There are two types of listability - the one in built-in functions, which pushes threading into the kernel and is fast, and the top-level one (setting Listable for some functions by the user).

You can not achieve built-in listability by simply setting a Listable attribute. The reason is that, while the end result is the same - automatic threading over lists, the underlying mechanisms to achieve it are different for built-ins vs user-defined. When a built-in Listable function (particularly numerical) is passed lists as arguments, it dispatches to the special branch which internally runs the loop, and returns a list of results. So, for a built-in function, Listable is rather a signal to pick the internal branch which deals with lists automatically.

It seems that the absence of Listable does not prevent this "internal branch" from being used.

$\endgroup$
5
  • $\begingroup$ I think in this case, you make in Listable,because trace it will give me {f[{1,2,3}],f/@{1,2,3},{f[1],f[2],f[3]}}. $\endgroup$
    – luyuwuli
    Jan 12, 2015 at 13:33
  • $\begingroup$ @luyuwuli But f does not have the Listable attribute, it only behaves (somewhat) like it does, and that was my point. $\endgroup$
    – Mr.Wizard
    Jan 12, 2015 at 13:34
  • $\begingroup$ According to your edit, did you mean that there are lower-level map function implemented in the kernel so that it can auto-thread even without the Listable attributes? $\endgroup$
    – luyuwuli
    Jan 12, 2015 at 13:37
  • $\begingroup$ @luyuwuli I am not the one who wrote that, Leonid Shifrin is, but as I understand it, yes. $\endgroup$
    – Mr.Wizard
    Jan 12, 2015 at 13:39
  • 1
    $\begingroup$ I always understood the Listable attribute in these cases as mainly a courtesy to user code rather than a requirement for proper evaluation. After all, if a function behaves as if Listable, it's not really helpful if the attribute is missing, but you can of course always have a function with specialized definitions for different types of inputs regardless of that. Or, perhaps Sqrt implements an explicit loop over depth-1 lists, but not for higher-dimensional structures, so that it is part specialized, and part top-level Listable. This would be a reasonable optimization, IMO. $\endgroup$ Jan 12, 2015 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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