you are good! Based on your comments, I crafted this:
Block[{Equal, H = Developer`ToPackedArray},
SetAttributes[Equal, Listable];
Equal[x_H, y_H] :=
Equal[Developer`FromPackedArray[x], Developer`FromPackedArray[x]];
a == b]
which works in both cases.
Update
Mr.Wizard said " I expected symbols localized with Block to behave generically." Although the above works, as mentioned in the comments, there is an observable difference between Equal
and other user defined symbols in the rewrite/eval loop in regards to Listable
and automatic unpacking of packed arrays. I played with different definitions and couldn't find why this happens.
Clear[f, g, h, z1, z2];
ClearAttributes[{z1, z2}, {Listable}];
f[a_, b_] := Block[{Equal, H = Developer`ToPackedArray},
SetAttributes[Equal, Listable];
Equal[x_H, y_H] :=
Equal[Developer`FromPackedArray[x],
Developer`FromPackedArray[x]];
Print[ a == b // FullForm];
a == b];
g[a_, b_] := Block[{Equal, H = Developer`ToPackedArray},
SetAttributes[Equal, Listable];
Print[ a == b // FullForm];
a == b];
h[a_, b_] := Block[{Equal = z1, H = Developer`ToPackedArray},
SetAttributes[z1, Listable];
Print[ a == b // FullForm];
a == b] /. z1 -> Equal;
i[a_, b_] := Block[{Equal = z2, H = Developer`ToPackedArray},
SetAttributes[Equal, Listable];
Print[ a == b // FullForm];
a == b] /. z2 -> Equal;
Then I did
{a , b } = {{1, 2}, {1, 3}};
{c , d} = Developer`ToPackedArray /@ {a, b};
which produces,
In[211]:= f[a, b]
List[Equal[1,1],Equal[2,3]]
Out[211]= {True, False}
In[212]:= f[a, c]
List[Equal[1,1],Equal[2,2]]
Out[212]= {True, True}
In[213]:= g[a, b]
List[Equal[1,1],Equal[2,3]]
Out[213]= {True, False}
In[214]:= g[a, c]
Equal[List[1,2],List[1,2]]
Out[214]= True
In[215]:= h[a, b]
List[z1[1,1],z1[2,3]]
Out[215]= {True, False}
In[216]:= h[a, c]
List[z1[1,1],z1[2,2]]
Out[216]= {True, True}
In[217]:= i[a, b]
z2[List[1,2],List[1,3]]
Out[217]= False
In[218]:= i[a, c]
z2[List[1,2],List[1,2]]
Out[218]= True
So one can see that there is a difference between g[a,c]
and h[a,c]
: in g Equal
does not unpack, whereas in h the user-defined z1 does. I think all the other behaviours can be explained from the evaluation (rewrite) steps as explained in the Mathematica documentation.
Anyway, just wanted to comment finally that although Mr Wizard's is a fair claim. There are a number of areas where other than pure symbolic/rewrite manipulation is occurring, and that simply Block
is not probably considering. For example -hope not to trivial for you-, Block[{Equal}, ToExpression["?Equal"]]
still prints the Equal
documentation, instead of a reference to an undefined symbol. So, like in this case, maybe Equal
(and other built-ins) have special behaviour which Block
is not touching.
Sorry, I will leave it as answer, but now probably I should say it is not...
Update 2
Actually, just checked that Block
leaves ::usage untouched! So, if you do
f::usage = "Symbol f";
then
Information[f]
Symbol f
And if you do Block
still you get the same
Block[{f}, Information[f]]
Symbol f
so Block
and Information
are not working together, even for user-defined symbols!
Last update
As noticed by some, symbols like Plus
have special behaviour too. So this
Block[{Plus}, Print[Trace[Plus[1, 2]]]]; (* 1 *)
Block[{Global`Plus}, Print[Trace[Plus[1, 2]]]]; (* 2 *)
Block[{Global`Plus}, Print[Trace[Global`Plus[1, 2]]]]; (* 3 *)
produces
{1+2,3}
{1+2,3}
{}
which demonstrates that Plus
retains the built-in behaviour in 1 and 2, being really overridden only with a syntax like 3, which is not convenient. By the way, 2 generates a warning.
Bottom, line, to answer Mr.Wizard's request -I believe this answer was suggested in the comments- it seems the only generic way to override a built-in is to provide your own user defined symbol instead. If one wants to redefine, say Plus, IMHO it is not a burden as whatever definition one wants to introduce can be done with the user-defined symbol and still one has the convenience of the syntactic sugar. To wit
Block[{Plus = plus}, plus[0, _] := 0; Print[Trace[0 + 2]]];
which produces
{{Plus,plus},plus[0,2],0}
So, I will leave it like this.
Block[{Equal},SetAttributes[Equal, Listable];Equal[a_,b_]:=Hold[Equal[a,b]];A==B]//ReleaseHold
gives{{{False, False}, {False, True}, {False, True}}, {{False, False}, {False, False}, {True, False}}, {{False, True}, {False, False}, {False, False}}, {{False, True}, {False, False}, {False, True}}}
$\endgroup$Trace
on your expression v. Mr. Wizard's shows that by redefiningEqual
, as you do, it is actually threaded over the lists, yet Mr. Wizard's is not. UsingSetSystemOptions["PackedArrayOptions" -> "UnpackMessage" -> True]
reveals that in both cases some unpacking does occur, but in Mr. W's case we get "Unpacking array with dimensions {1}" v. "Unpacking array with dimensions {4,3,2} in call to Equal" in your case. By redefiningEqual
it automatically unpacks the full array. $\endgroup$