Re: Re: Re: Define an antisymmetric function

```Another alternative is:

G[a, b] := f[a, b]
G[a, c] := g[a, c]
G[b, c] := h[b, c]
G[a_, b_] /; Signature[{a, b}] == -1 := -G[b, a]

It requires that you give literal definitions for the signature 1
ordering of arguments.

Carl Woll
Wolfram Research

On 2/12/2010 4:46 AM, Leonid Shifrin wrote:
> Hi Torsten,
>
> here is a little more high-level variation of Szabolcs's solution, which
> isn't robust either, since it assumes only Downvalue - based definitions and
> that you will not add more general (pattern-based) definitions to G later
> on.
>
> ClearAll[G];
> G[a, b] := f[a, b]
> G[a, c] := g[a, c]
> G[b, c] := h[b, c]
> G[x_, y_] := -G[y, x] /;
>    Hold[G[y, x]] =!= (Hold[G[y, x]] /. Most@DownValues[G])
>
> It may however be a little faster since the specific rules (without
> patterns) in DownValues are
> hash-table based and therefore the rule look-up should be constant time in
> the size of the definition list.
>
> Out of curiosity, I also tried to  address a different fomulation of your
> problem, where for unknown
> arguments the function must use antisymmetry, but just once:
> G[x,y]->-G[y,x]. The following
> hack seems to do it:
>
> In[318]:= Clear[GG];
>
> GG[a,b]:=f[a,b]
> GG[a,c]:=g[a,c]
> GG[b,c]:=h[b,c]
>
> Module[{tried, reset},
>   reset[] := (Clear[tried]; tried[_, _] = False);
>   reset[];
>   GG[x_, y_] /; ! tried[x, y] := (tried[y, x] = True; -GG[y, x]);
>   GG[x_, y_] := "" /; reset[];
>   ]
>
> In[323]:= GG[a,b]
>
> Out[323]= f[a,b]
>
> In[324]:= GG[b,a]
>
> Out[324]= -f[a,b]
>
> In[325]:= GG[d,e]
>
> Out[325]= -GG[e,d]
>
> In[326]:= GG[e,d]
>
> Out[326]= -GG[d,e]
>
> One problem with it is that it may keep some garbage in<tried>  for
> arguments on which
> GG has been defined (a,b,c here) - it will still work but consume a little
> extra memory.
>
> Regards,
> Leonid
>
>
> 2010/2/11 Szabolcs Horv=E1t<szhorvat at gmail.com>
>
>
>> On 2010.02.11. 12:53, Torsten Schoenfeld wrote:
>>
>>> I'd like to define an antisymmetric function by giving its value on a
>>> set of known objects.  I'm having trouble enforcing antisymmetry.  Say I
>>> want to define G[_, _] on the objects {a, b, c}:
>>>
>>>      G[a, b] := f[a, b]
>>>      G[a, c] := g[a, c]
>>>      G[b, c] := h[b, c]
>>>
>>> If I now enforce antisymmetry simply by
>>>
>>>      G[x_, y_] := -G[y, x]
>>>
>>> then it mostly works (e.g., G[b, a] evaluates to -f[a, b]).  But if I
>>> apply G to something that is not in {a, b, c}, then I run into an
>>> infinite loop: G[a, f[b]] yields "\$RecursionLimit::reclim: Recursion
>>> depth of 256 exceeded."
>>>
>>> Ideally, I would like applications to unknown input to stay unevaluated
>>> (e.g., G[a, f[b]] just yields G[a, f[b]]).  How can I achieve that while
>>> also enforcing antisymmetry?
>>>
>>>
>> Hello Torsten,
>>
>> I do not think that it is possible to do this in a general way.  It
>> might, however, be possible to make it work for the special cases that
>> you need.
>>
>> The reason why it is not possible to implement it in a completely
>> general way is this:
>>
>> Suppose we input G[a,b], and suppose that there is no definition
>> associated with G that would allow computing the value of G[a,b].  Now
>> we need to check if G[b,a] can be computed, and if so, then use the
>> value -G[b,a] for G[a,b].  But how can we check if G[b,a] "can be
>> computed", that is, if it evaluates to something different than itself?
>>   If we aim for complete generality, this is only possible by trying to
>> evaluate G[b,a], which will then trigger the antisymmetry definition
>> again, and lead to infinite recursion...
>>
>> So, let's not aim for completely generality.  Instead, let's just check
>> if an *explicit* definition exists for G[b,a] (i.e. for the explicit
>> values b and a):
>>
>> G[x_, y_] := -G[y, x] /; hasValue[G[y,x]]
>>
>> hasValue[f_[args___]] :=
>>   MemberQ[First /@ DownValues[f], Verbatim@HoldPattern[f[args]]]
>>
>> This will work for simple cases, but it is neither pretty, nor robust.
>> I hope someone will post a better suggestion.
>>
>> One more thing that needs to be mentioned is that there is already a
>> function similar to hasValue[] built into Mathematica:  ValueQ[].
>> However, it cannot be used here because for non-atomic arguments
>> (anything more complicated than a symbol) it determines if it has a
>> value by evaluating it and checking whether it has changed.  So the
>> infinite recursion still wouldn't be avoided.
>>
>> I hope this helps,
>> Szabolcs
>>
>>
>>
>

```