First time here? Check out the FAQ!

Ask Your Question
1

Root systems algorithm: "TypeError: 'str' object is not callable"

asked 4 years ago

SarahDi gravatar image

updated 4 years ago

slelievre gravatar image

I am rather new to Sage and formal language.

I am running the following code which works fine with a slighty simpler version (where the variables p1, p2, ..., p5 in the function letsapply are fixed).

Here is the original function that works fine:

def letsapply(listg, alist):
    mylistg = listg
    mylistg.reverse()
    for si in mylistg:
        if si == 's1':
            alist = map(s1, alist)
        elif si == 's2':
            alist = map(s2, alist)
        elif si == 's3':
            alist = map(s3, alist)
        elif si == 's4':
            alist = map(s4, alist)
        elif si == 's5':
            alist = map(s5, alist)
        elif si == 's6':
            alist = map(s6, alist)
        else:
            print("Wrong input in letsapply!!")
    alistt = [tuple(v) for v in alist]
    alistts = set(alistt)
    return alistts

Below, I am getting the following

TypeError: 'str' object is not callable

Could anyone help me fix this? Thanks a lot!

e = RootSystem(['E',6]).ambient_space()
Roots = e.roots()

a1 = vector((1/2, -1/2, -1/2, -1/2, -1/2, -1/2, -1/2, 1/2))
a2 = vector((1, 1, 0, 0, 0, 0, 0, 0))
a3 = vector((-1, 1, 0, 0, 0, 0, 0, 0))
a4 = vector((0, -1, 1, 0, 0, 0, 0, 0))
a5 = vector((0, 0, -1, 1, 0, 0, 0, 0))
a6 = vector((0, 0, 0, -1, 1, 0, 0, 0))

Lini = [a1, a2, a3, a4, a5]

# alist is the set of all projections of roots in E6

myR = [vector(v) for v in Roots]

def proj(t, ai):
    myLone = vector(ai)
    result= t - myLone.dot_product(t) / (ai.dot_product(ai))*myLone
    return result

myL = [proj(x, a6) for x in myR]

def si(t, projai):
      myLone = projai
      result = t- 2*myLone.dot_product(t)/(projai.dot_product(projai))*myLone
      return result

def decompose(g, mylength):
    # g is a str(aa) where aa belongs to list(WeylGroup ...)
    listg = [g[3*i]+ g[3*i+1] for i in range(0, mylength)]
    return listg

def letsapply(listg, alist, p1, p2, p3, p4, p5):
    mylistg = listg
    mylistg.reverse()
    for si in mylistg:
        if si == 's1':
            alist = map(lambda w: si(w, p1), alist)
        elif si == 's2':
            alist = map(lambda w: si(w, p2), alist)
        elif si == 's3':
            alist = map(lambda w: si(w, p3), alist)
        elif si == 's4':
            alist = map(lambda w: si(w, p4), alist)
        elif si == 's5':
            alist = map(lambda w: si(w, p5), alist)
        else:
            print("Wrong input in letsapply!!")
    alistt = [tuple(v) for v in alist]
    alistts = set(alistt)
    return alistts

def main():
    W = WeylGroup(["A", 5], prefix="s")
    listW = list(W)
    # We remove the first element which is 1:
    listW.pop(0)
    listWdecomposed = [decompose(str(g), g.length()) for g in listW]

    e = RootSystem(['E',6]).ambient_space()
    Roots = e.roots()
    ## get all projections of roots in E6
    myR = [vector(v) for v in Roots]
    myL = [proj(x, a6) for x in myR]
    print("myL =", myL)

    # produce all combinaisons in myL of five vectors,
    # and apply the procedure to them: the procedure consists first in writing
    # the Weyl group associated to any five elements in myL (call any : myLel),
    # then applying these elements si to myLel

    myLlist= Combinations(myL, 5).list()
    for myLel in myLlist:
        [proja1, proja2, proja3, proja4, proja5] = myLel
    res = set(tuple(v) for v in myLel)
    for listg in listWdecomposed:
        res = res.union(letsapply(listg, myLel, proja1, proja2, proja3, proja4, proja5))
        # Reconvert
        res = [vector(v) for v in res]
        res.sort()
    if len(res)< 30:
        return(len(res), res)
    else:
        print("too many vectors in this subspace")
    return 0
    main()
Preview: (hide)

1 Answer

Sort by » oldest newest most voted
1

answered 4 years ago

Emmanuel Charpentier gravatar image

Your code self-contradicts. Take this sample :

for si in mylistg:
    if si == 's1':
        alist = map(s1, alist)

The second line triggers the execution of the third if the test succeeds, i. e if si is a string.

But the third line then tries to map the function si to the elements of alist.

You can't have it both ways : si can't be simultaneously a string and a function...

You have to choose to have your cake or to eat it...

A possible solution is to make mylistg a list of functions, and have allowed_s a list of permissible values. You code snippet would become (something like)

alisttt=[list(map(lambda v:u(v), alist)) for u in mylistg if u in allowed_s]

with possible seasonings to prepare the arguments and return the result in pleasant form.

HTH,

Historical (paleontological) note : Common Lisp, allowing you to attach both a value and a function to the same symbol, would have allowed such a ... thing ... Not Python.

Preview: (hide)
link

Comments

Hi, the si applied is the si defined here:

myP = [proj(x, a6) for x in Lini]
 [proja1, proja2, proja3, proja4, proja5] = myP
    def si(t, projai):
            myLone = projai
            result = t- 2*myLone.dot_product(t)/(projai.dot_product(projai))*myLone
            return result
SarahDi gravatar imageSarahDi ( 4 years ago )

This code along with the main function below work fine:

def main():
    W = WeylGroup(["A", 5], prefix="s")
    listW = list(W)
    # We remove the first element which is 1:
    listW.pop(0)
    listWdecomposed = [decompose(str(g), g.length()) for g in listW]
    res = set(tuple(v) for v in myP)

    for listg in listWdecomposed:
        res = res.union(letsapply(listg, myP))

    # On reconvertit :
    res = [vector(v) for v in res]
    res.sort()
    return(len(res), res)

Now, I am trying to do a loop where I apply this function 'main' to the list of all sets of five random vectors in myL, this is why I have added the p1,p2... in the letsapply function.

SarahDi gravatar imageSarahDi ( 4 years ago )

If I understand you correctly, you oscillate between the generators of W (here s1, s2, s3, s4, s5) and their string representations (i. e. "s1", "s2", "s3", "s4", "s5"). Your function decompose is an attempt to get to the "factors" of a (non-trivial) element of W in terms of these generators.

Let's keep it simple, stay in W and do not fiddle with string representation madness :

sage: W=WeylGroup(["A",5], prefix="s")                                          
sage: def decompose(w): 
....:     S=w.parent().gens() 
....:     return [S[u-1] for u in w.reduced_word()] 
....:                                                                           
sage: all([bool(w==product(decompose(w))) for w in W[1:]])                      
True

HTH,

Emmanuel Charpentier gravatar imageEmmanuel Charpentier ( 4 years ago )
1

OK, I'm dense, and wasn't clear the first time around.

In your function letsapply, the snippet :

for si in mylistg:
    if si == 's1':
        alist = map(s1, alist)

defines si to be a local variable (with a string value coming from mylistg). This variable hides the global definition of the function si, which is no longer reachable, hence the dreaded string not callable message.

Rename your bloody loop variable !

Is that clearer ?

Now,

  • Messing with string representations of objects is still objectionable. Use the natural bases and natural representation of your objects.

  • A Python dictionary whose keys are the elements of the basis of your objects and whose value would be the associated functions would be both clearer and more natural.

Emmanuel Charpentier gravatar imageEmmanuel Charpentier ( 4 years ago )

Cool. Merci :)

SarahDi gravatar imageSarahDi ( 4 years ago )

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

Stats

Asked: 4 years ago

Seen: 1,148 times

Last updated: Sep 24 '20