# using @interact to enter some information in election system

The following code gives the candidat who must be eliminated in a *Nanson election *.

def Nanson_one(cand, partisans,code):
Scand=sorted(Set(cand))
ncand=len(cand)
All_pref=Arrangements(Scand,ncand).list()
All_pref_with_index = [(i,All_pref[i]) for i in range(len(All_pref))]
rank=[[(list(All_pref[i]).index(cand[j]))+1 for i in range(len(All_pref))] for j in range(len(cand))]
score =  piecewise([([i,i], ncand+1-i) for i in range(ncand+1)])
scores=[[partisans[i]*score(rank[j][i]) for i in range(len(All_pref))] for j in range(len(cand))]
augmented_scores = [scores[i]+[totscore[i]] for i in range(len(cand))]
ahr=[i for i in range(len(All_pref))]+["$\\text{Total}$"]
minvote = min(totscore)
candidat_éliminé=min(totscore)
indice_candidat_éliminé=totscore.index(min(totscore))
nom_candidat_éliminé=cand[indice_candidat_éliminé]
if code == 1 :
return table(augmented_scores,header_row=ahr,header_column=["$\\stackrel{\\normalsize Préf}{Cand}$","$\\boldsymbol{A}$","$\\boldsymbol{B}$","$\\boldsymbol{C}$","$\\boldsymbol{D}$"])
elif code == 2 :
show(LE(r"\text{Le candidat éliminé est le candidat }"), nom_candidat_éliminé, LE(r"\text{ qui n'a reçu que }"),minvote,LE(r"\text{ votes.}"))
elif code == 3 :
return nom_candidat_éliminé


code = 1 gives the table of scores

code =2 gives the name of the candidat who must be excluded.

In what concerns passing the cand parameter, there is no difficulty it must be

cand = ["A","B","C","D"]


For partisans parameter it's much involved, since it correspond to the number of electors whose preferences are ABCD, ACBD, ACDB... For teaching purpose, it is necessary to construct a list of number whise entries correspond to the number of voters for ABCD...

I have seen that input is possible with @interactbut the display is elementary and works for small matrix. Here I need the some information (the ABCD's) be above the cell which must be documented (by default it is zero).

I can do it manualy as demonstrated by the following code :

cand = ["A","B","C","D"]
All_pref=Arrangements(Scand,ncand).list()
LE=LatexExpr
All_pref_with_index = [(i,All_pref[i]) for i in range(len(All_pref))]
show(LE(r"\text{Toutes les préférences sont possibles} "))
show(All_pref_with_index)
#Toutes les entrées de partisans sont mises à 0 puis on rajoute celles qu'on veut.
partisans=[0 for i in range(len(All_pref))]
partisans[1]=25
partisans[10]=15
partisans[12]=5
partisans[16]=12
partisans[23]=3
hr=[i for i in range(len(All_pref))]

show(LatexExpr(r"\text{Le nombre des électeurs qui adoptent les préférences sont :}"))
table([partisans], header_row=hr,header_column=[r"$\text{Indice des préférences }",r"$\text{Nombre d'électeurs}"],frame=true)


but I think it will be better if my student can change thge number of electors in an @interact cell.

But if there is no solution it's not a big problem. Now my true problem is the following:

the result of Nanson_one(cand, partisans,3) is the name of the eliminated candidate. So I must drop its name from the list cand. Here is the code

cand.remove(Nanson_one(cand, partisans,3))


and this works. But if I try to allocate

cand1=cand.remove(Nanson_one(cand, partisans,3))


when I try to display it I obtain nothing.

Hope to have been clear and to have given all needed information.

edit retag close merge delete

( 2020-12-23 00:37:30 +0200 )edit

Sort by » oldest newest most voted

Hello, @Cyrille! Let me answer the second part of your question. The problem with the syntax

cand1 = cand.remove(Nanson_one(cand, partisans,3))


is that cand.remove() is a statement, but not an expression. Generally speaking (not formally), statements are instructions given to the language to perform a task, like print('Hello, world') or 2 + 3, while expressions are all those statements that return a value. For example, print('Hello, world') does not return any value (it just prints the words "hello, world"), while 2 + 3 returns the value 5.

Now, this previous explanation is not 100% true. Python actually has the None value for statements that are not expressions (confusing, I know). However, this is a quite useful feature, since it can help you know if a particular statement is an expression. For example, if you write

print(2 + 3)


you will see the value 5, indicating that 2 + 3 (not print(2 + 3)) is an expression. However, if you write

A = [1, 2, 3, 4]
print(A.remove(3))


you will see None in your screen, indicating this is not an expression. This means A.remove(3) performs the task of removing the 3 from the list A, but does not return any value as a result.

That's the problem with your statement

cand1 = cand.remove(Nanson_one(cand, partisans,3))


since it is removing the less voted candidate from the list cand, and then it does not return any value (actually returns None, as just explained), which is assigned to cand1, so cand1 is None or nothing.

The solution is to separate the operation into two lines:

cand.remove(Nanson_one(cand, partisans,3))
cand1 = cand


Now, this also causes some problems: you should be very careful about aliasing. Let me explain really quickly. Consider this code:

A = [1, 2, 3, 4]
B = A
A.remove(3)
print('A =', A)
print('B =', B)


Intuitive thought suggest that $A = [1, 2, 4]$ and $B = [1, 2, 3, 4]$ after this code is executed, but that is not correct (try it!). Lists, like A and cand are mutable data types, which means that B = A does not create a copy of A and assigns that copy to B, but actually creates a "new name" or "alias" for A. In simple terms, A and B are the same list, and modifying one of them, modifies the other in the same way, and viceversa. If you want to avoid aliasing, you should write

A = [1, 2, 3, 4]
B = A[:]
A.remove(3)
print('A =', A)
print('B =', B)


The choice of aliasing vs. not aliasing is a matter of what you want your code to do. Unfortunately, I don't have enough information about your code to help you with that. (Perhaps it is even unnecessary to consider this.)

Anyway, concerning the first part of your question, I am not completely sure if this is what you want, but I believe that you want something like this code. (Note: I made some modifications to your code in order to make it easier for me to program it.) If this is indeed the code you need, please, let me know so I can add it here with an explanation. Also, let me know if you require some specific modification.

I hope this helps!

Edit: The previous code answers the question only partially. Unfortunately, I haven't found a practical way to add labels to the interactive cells in the SageCell Server. Doing this seems easier in a local Sage installation running Jupyter(Lab); however, I believe that's the for the purposes of another question.

more

Diego thanks for your great answer. I will study it as soon as I finished to correct copies. But in the @interact part what I would like is that the number of the cell be displayed above or under the cell.

( 2020-12-29 10:57:29 +0200 )edit

Hello, @Cyrille! Sorry for the delayed answer. I have tried different approaches to display labels for the cells. Unfortunately, I have failed. Here is the problem: SageCell and Jupyter(Lab), which are the two main Sage's notebook interfaces use different approaches to deal with this kind of cell grids. In the case of SageCell, I am afraid that doing what you want requires a deep knowledge of the internal code (at least, a deeper knowledge that my own), and perhaps a little bit of HTML (?) I would suggest opening an issue in the SageCell repository requesting this feature. On the other hand, I believe that doing this in Jupyter(Lab) is easier, but only works on your local computer.

( 2021-01-04 05:56:53 +0200 )edit

Perhaps you could edit your question to highlight the fact that you need labels for the interactive cells.

( 2021-01-04 06:04:52 +0200 )edit