From: Bob Hanlon on 12 Feb 2010 04:39 G[a, b] := f[a, b]; G[a, c] := g[a, c]; G[b, c] := h[b, c]; G[x_, y_] := -G[y, x] /; MemberQ[{a, b, c}, x] && MemberQ[{a, b, c}, y] && (x =!= y) G @@@ {{a, b}, {b, a}, {a, a}, {a, x}, {a, f[b]}} {f[a, b], -f[a, b], G[a, a], G[a, x], G[a, f[b]]} Bob Hanlon ---- Torsten Schoenfeld <kaffeetisch(a)gmx.de> 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?
From: David Park on 12 Feb 2010 04:39 G[a, b] := f[a, b] G[a, c] := g[a, c] G[b, c] := h[b, c] G[x_, y_] /; \[Not] OrderedQ[{x, y}] := -G[y, x] {G[a, b], G[b, a], G[c, b], G[a, f[b]], G[f[b], a]} {f[a, b], -f[a, b], -h[b, c], G[a, f[b]], -G[a, f[b]]} David Park djmpark(a)comcast.net http://home.comcast.net/~djmpark/ From: Torsten Schoenfeld [mailto:kaffeetisch(a)gmx.de] 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?
From: Torsten Schoenfeld on 12 Feb 2010 05:44 On 12.02.10 10:45, Leonid Shifrin wrote: > 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(a)DownValues[G]) This actually works perfectly fine even if pattern-based definitions are involved! (Pattern-based definitions appear normally in DownValues.) I neglected to mention it, but G[_, _] is also supposed to act as a derivative in both slots, e.g. G[x_, y_^2] := 2 G[x, y] y. Your approach handles this gracefully: G[x^2, y] yields -2 x G[y, x]. So, thanks a lot! Thanks also for all the other suggestions in this thread; I learned many nice tricks.
From: Szabolcs on 12 Feb 2010 06:58 On Feb 12, 11:44 am, Torsten Schoenfeld <kaffeetisch(a)gmx.de> wrote: > On 12.02.10 10:45, Leonid Shifrin wrote: > > > 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(a)DownValues[G]) > > This actually works perfectly fine even if pattern-based definitions are > involved! (Pattern-based definitions appear normally in DownValues.) I > neglected to mention it, but G[_, _] is also supposed to act as a > derivative in both slots, e.g. G[x_, y_^2] := 2 G[x, y] y. Your > approach handles this gracefully: G[x^2, y] yields -2 x G[y, x]. > > So, thanks a lot! Thanks also for all the other suggestions in this > thread; I learned many nice tricks. I believe that what Leonid referred to when he said that it might not work if you add pattern based definitions later on was that this approach assumed that the "antisymmetry definition" is the very last one in the DownValue list. Mathematica tries to automatically order definitions from most specific to most general, but this is not always possible. When it can't do this, it just adds rules to the DownValue list in the order they were defined. So a general pattern based definition *may* displace the antisymmetry rule from the very last position, especially if it is added later. Just be careful with the order in which definitions are made.
From: Carl K. Woll on 13 Feb 2010 05:21 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(a)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(a)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(a)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 >> >> >> >
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: How to scope PopupMenu values in a DynamicModule? Next: manipulate plot |