From: Torsten Schoenfeld on 11 Feb 2010 06:53 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: Szabolcs Horvát on 11 Feb 2010 08:07 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
From: Daniel Lichtblau on 12 Feb 2010 04:40 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? > One way to do this is to only assign to the ordered set of arguments, then impose down values to handle out-of-order argument lists. For the case of two arguments this can be done as below. assignOrdered[G_,a_,b_,f_] := If[a===b, G[a,b] := 0, If [OrderedQ[{a,b}], G[a,b] := f[a,b], G[b,a] := -f[a,b]]] Here I replicate your assignments, plus another which gives the arguments in non-OrderedQ form. assignOrdered[G,a,b,f] assignOrdered[G,a,c,g] assignOrdered[G,b,c,h] assignOrdered[G,d,c,k] Now we impose antisymmetry. G[a_,a_] := 0 G[a_,b_] /; !OrderedQ[{a,b}] := -G[b,a] let's see what we have. In[61]:= DownValues[G] Out[61]= {HoldPattern[G[a, b]] :> f[a, b], HoldPattern[G[a, c]] :> g[a, c], HoldPattern[G[b, c]] :> h[b, c], HoldPattern[G[c, d]] :> -k[d, c], HoldPattern[G[a_, a_]] :> 0, HoldPattern[G[a_, b_] /; !OrderedQ[{a, b}]] :> -G[b, a]} Quick test: In[62]:= {G[x,y], G[y,x], G[c,d],G[d,c],G[x,a]} Out[62]= {G[x, y], -G[x, y], -k[d, c], k[d, c], -G[a, x]} Daniel Lichtblau Wolfram Research
From: Albert Retey on 12 Feb 2010 04:45 Hi, > 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? I think your problem is that G[x_, y_] := -G[y, x] will result in a infinit recursion, since part of the right hand side will match the left hand side no matter what arguments you give. To enforce antisymmetry you could do this, so the pattern will match only when the arguments are not in canonicial order: g[b_, a_] /; Not[OrderedQ[{b, a}]] := -g[a, b] hth, albert
From: Leonid Shifrin on 12 Feb 2010 04:45 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 > >
|
Next
|
Last
Pages: 1 2 3 Prev: How to scope PopupMenu values in a DynamicModule? Next: manipulate plot |