import numpy as np
import sage.all
class DiceNonTransitive(object):
'''
three dice in diceT, an join the dice color
diceT=[[3,3,3,3,3,6],[1,4,4,4,4,4] ,[2,2,2,5,5,5]]
diceColorT=['Red','Green','White']
https://ocw.mit.edu/courses/mathematics/18-05-introduction-to-probability-and-statistics-spring-2014/assignments/MIT18_05S14_ps1.pdf
https://www.youtube.com/watch?v=zWUrwhaqq_c
https://en.wikipedia.org/wiki/Partition_(number_theory)
finally diceMatchT should not be in the constructor !
if diceMatchT=None
self.diceMatchT=[2,2,0]
diceColorT=['Red','Green','White']
diceMatchT is [2,0,2] means 2 red dice against 2 white dice
diceMatchT is [1,1,0] means 1 red die against 1 green die
diceMatchT is [0,1,1] means 1 green die against 1 white die
diceMatchT is [3,0,3] means 3 red dice against 3 white dice
'''
def __init__(self,diceT=None,diceColorT=None):
self.diceT=diceT
self.diceColorT=diceColorT
if self.diceT==None :
self.diceT=[[3,3,3,3,3,6],[1,4,4,4,4,4] ,[2,2,2,5,5,5]]
if self.diceColorT==None :
self.diceColorT=['Red','Green','White']
""" finally diceMatchT should not be in the constructor !
if diceMatchT=None
self.diceMatchT=[2,2,0]
diceColorT=['Red','Green','White']
diceMatchT is [2,0,2] means 2 red dice against 2 white dice
diceMatchT is [1,1,0] means 1 red die against 1 green die
diceMatchT is [0,1,1] means 1 green die against 1 white die
diceMatchT is [3,0,3] means 3 red dice against 3 white dice
"""
self.diceMaskT=[]
for dieSet in self.diceT:
self.diceMaskT.append([i for i in range(len(dieSet))])
self.expectationT=[]
self.expectationRoundedT=[]
for die in self.diceT :
self.expectationT.append(sum(die)/6)
self.expectationRoundedT.append(round(sum(die)/6,3))
#show("Dice Expectation: ",ExpectationT)
#show("Dice Expectation Rounded: ",ExpectationRoundedT)
self.diceValueFrequencyT=[]
for die in range(0,len(self.diceT)) :
freqT = np.array(self.diceT[die])
# array multiplication term by term with numpy with SageMath Integer format setting
valueT = [sage.all.Integer(a) for a in np.bincount(freqT)]
nonZeroValueT=[sage.all.Integer(a) for a in np.nonzero(valueT)[0]]
#show(valueT)
#show("nonZeroValueT : ",nonZeroValueT)
# example if diceT=[[3,3,2,2,3,6],[1,4,4,4,4,4] ,[2,2,2,5,5,5]]
# then the Dice Frequency values Table will be :
#[[[2, 1/3], [3, 1/2], [6, 1/6]], [[1, 1/6], [4, 5/6]], [[2, 1/2], [5, 1/2]]]
self.diceValueFrequencyT.append([([nonZeroValueT[value],((valueT[nonZeroValueT[value]])/ (len(self.diceT[die])))]) for value in range(0,len(nonZeroValueT)) ])
# this code below re-arrange the value and their frequency in two lists
# one list for values and its corresponding frequency list
#example:
#diceT=[[3,3,1,3,3,6],[1,4,4,4,4,4] ,[2,2,2,5,5,5]]
#diceColorT=['Red','Green','White']
# then the two arrays will be :
#ππ½ππ π:[[1,3,6],[1,4],[2,5]]ππ½ππ π:[[1/6,2/3,1/6],[1/6,5/6],[1/2,1/2]]
self.vNewT=[]
self.fNewT=[]
for die in range(0,len(self.diceT)) :
vT=[]
fT=[]
for vf in self.diceValueFrequencyT[die] :
#show("f : ",vf," f len : ",len(vf)," f[0] : ",vf[0])
vT.append(vf[0])
fT.append(vf[1])
self.vNewT.append(vT)
self.fNewT.append(fT)
def getDieFrequencyValue(self,die,value) :
"""this function return the frequency contained in one of the three dice
die=0,1,2 and return -1 if the die does not contain the value"""
#show(diceT[die][v])
valueIndex = None
try:
valueIndex=self.vNewT[die].index(value)
frequency=self.fNewT[die][valueIndex]
#show("die number : ",die," index : ",valueIndex, " frequency : ",frequency)
return frequency
except ValueError:
print("List does not contain value : "+str(value))
return -1
"""
this function below returns two list one is the self die value arrangement combinations
the other is their corresponding frequencies
Example if :
diceT=[[7,3,3,3,3,6],[1,7,4,4,4,4] ,[2,2,7,5,5,5]]
diceColorT=['Red','Green','White']
ππ½ππ π:[[3,6,7],[1,4,7],[2,5,7]]
ππ½ππ π:[[2/3,1/6,1/6],[1/6,2/3,1/6],[1/3,1/2,1/6]]
then if die=0 here [3,6,7] and dice number=2, means 2 self dices combinations
diceValueCombinationT,diceFrequencyCombinationT will be
([[πΉ,πΉ],[πΉ,πΌ],[πΉ,π½],[πΌ,πΉ],[πΌ,πΌ],[πΌ,π½],[π½,πΉ],[π½,πΌ],[π½,π½]],
[[2/3,2/3],[2/3,1/6],[2/3,1/6],[1/6,2/3],[1/6,1/6],[1/6,1/6],[1/6,2/3],[1/6,1/6],[1/6,1/6]])
"""
def getDieItSelfCombinations(self,die,diceNumber) :
# diceNumber=number of same die rolls
vNewMultT=[]
for i in range(0,diceNumber) :
vNewMultT=vNewMultT+self.vNewT[die]
#show("vNewMultT : ",vNewMultT)
diceValueCombinationT=sage.all.Arrangements(vNewMultT,diceNumber).list()
#show(Arrangements(vNewMultT,diceNumber).list())
diceFrequencyCombinationT=[]
for i in range(0,len(diceValueCombinationT)) :
dieUple=[]
for j in range(0,len(diceValueCombinationT[i])) :
dieUple.append(self.getDieFrequencyValue(die,diceValueCombinationT[i][j]))
diceFrequencyCombinationT.append(dieUple)
return diceValueCombinationT,diceFrequencyCombinationT
def mult(self,T):
m=1
for t in T :
m=m*t
return m
""" this function execute getDiceFightResult for the three matchs
[[π·,π·,πΆ],[π·,πΆ,π·],[πΆ,π·,π·]]-> Red against Green, Red against White,Green against White
and gives in output a list like that for the three matchs: example for the diceT
[[3,3,4,3,1,4],[6,4,5,1,1,1],[4,2,2,3,3,4]]
the fourth value in one of the three lists (I mean here: 12,9,12) corresponds
to the number of branches of the tree covered by the dice match
[(5/12,4/9,5/36,12,1),(7/18,1/3,5/18,9,1),(4/9,1/2,1/18,12,1)]
and the threeDiceFightColorT list matchs=[[πππ,πΆππππ],[πππ,πππππ],[πΆππππ,πππππ]]"""
def getThreeDiceFightResult(self, diceMatchT) :
diceMatchCombinationT=sage.all.Arrangements(diceMatchT,len(diceMatchT)).list()
#show("diceMatchCombinationT : ",diceMatchCombinationT)
threeDiceFightT=[]
threeDiceFightColorT=[]
frequencyValueThreeDiceT=[]
for dMi in range(0,len(diceMatchCombinationT)) :
dieA,dieB=self.get2DiceNumber(diceMatchCombinationT[dMi])
#show("dieA,dieB : ",dieA," : ",dieB)
#show("diceMatchCombinationT:[dMi] : ",diceMatchCombinationT[dMi])
vA,fA=self.getDieItSelfCombinations(dieA,diceMatchCombinationT[dMi][dieA])
#show("vA,fA : ",vA," : ",fA)
vB,fB=self.getDieItSelfCombinations(dieB,diceMatchCombinationT[dMi][dieB])
#show("vB,fB : ",vB," : ",fB)
threeDiceFightT.append(self.getDiceFightResult(vA,fA,vB,fB))
threeDiceFightColorT.append([diceColorT[dieA],diceColorT[dieB]])
frequencyValueThreeDiceT.append([vA,fA,vB,fB])
return threeDiceFightT,threeDiceFightColorT,frequencyValueThreeDiceT
""" this function takes two results die A and die B of the function getDieItSelfCombinations
called twice for Two different dice, and gives in output the 3 results of the match
the proba of A wins again B, the proba of B wins against A, the proba of A=B,
and the number of branches of the tree of combinations that have been scanned
and the sum of 3 proba which must be equal to 1 !(for verification)
so five results """
def getDiceFightResult(self, diceValueCombinationAT,diceFrequencyCombinationAT, \
diceValueCombinationBT,diceFrequencyCombinationBT ) :
sumDiceValueCombinationAT=[]
for vA in diceValueCombinationAT:
sumDiceValueCombinationAT.append(sum(vA))
multDiceFrequencyCombinationAT=[]
for fA in diceFrequencyCombinationAT:
multDiceFrequencyCombinationAT.append(self.mult(fA))
sumDiceValueCombinationBT=[]
for vB in diceValueCombinationBT:
sumDiceValueCombinationBT.append(sum(vB))
multDiceFrequencyCombinationBT=[]
for fB in diceFrequencyCombinationBT:
multDiceFrequencyCombinationBT.append(self.mult(fB))
n=0
fAsupB=[];fAinfB=[];fAequB=[]
for pA in range(0,len(sumDiceValueCombinationAT)) :
for pB in range(0,len(sumDiceValueCombinationBT)) :
if sumDiceValueCombinationAT[pA] > sumDiceValueCombinationBT[pB] :
fAsupB.append(multDiceFrequencyCombinationAT[pA]*multDiceFrequencyCombinationBT[pB])
#show( "A > B f= ",fAsupB[-1])
elif sumDiceValueCombinationAT[pA]== sumDiceValueCombinationBT[pB] :
fAequB.append(multDiceFrequencyCombinationAT[pA]*multDiceFrequencyCombinationBT[pB])
#show( "A = B f= ",fAequB[-1])
else :
fAinfB.append(multDiceFrequencyCombinationAT[pA]*multDiceFrequencyCombinationBT[pB])
#show( "A < B f= ",fAinfB[-1])
n+=1
'''
show("sumDiceValueCombinationAT : ",sumDiceValueCombinationAT)
show("sumDiceValueCombinationBT : ",sumDiceValueCombinationBT)
show("multDiceFrequencyCombinationAT : ",multDiceFrequencyCombinationAT)
show("multDiceFrequencyCombinationBT : ",multDiceFrequencyCombinationBT)
'''
return sum(fAsupB),sum(fAinfB),sum(fAequB),n,sum([sum(fAsupB),sum(fAinfB),sum(fAequB)])
# this gives the 2 dice numbers in competition
# example : in input one of the three match [[πΆ,πΈ,πΈ] , [πΈ,πΆ,πΈ] , [πΈ,πΈ,πΆ]]
# will give in ouput One of the three 1,2 , 0,2 , 0,1
def get2DiceNumber(self,diceMatchT):
dieAB=[]
for d in range(0,len(diceMatchT)) :
if diceMatchT[d] !=0 :
dieAB.append(d)
dieA=dieAB[0]; dieB=dieAB[1]
return dieA,dieB
def testTransitiveThreeDiceFight(self, threeDiceFightT) :
t=False
"""this function test the non-transitivity of the three dice
πππππΌπππππ²πππππππππππ:[[π·,π·,πΆ],[π·,πΆ,π·],[πΆ,π·,π·]]"""
# TrigoWise
if threeDiceFightT[0][0] > threeDiceFightT[0][1] and \
threeDiceFightT[1][0] < threeDiceFightT[1][1] and \
threeDiceFightT[2][0] > threeDiceFightT[2][1] :
sage.all.show(threeDiceFightT[0][0]," > ",threeDiceFightT[0][1]) # Red > Green
sage.all.show(threeDiceFightT[1][0]," < ",threeDiceFightT[1][1]) # Red < White
sage.all.show(threeDiceFightT[2][0]," > ",threeDiceFightT[2][1]) # Green > White
t=True
# ClockWise
elif threeDiceFightT[0][0] < threeDiceFightT[0][1] and \
threeDiceFightT[1][0] > threeDiceFightT[1][1] and \
threeDiceFightT[2][0] < threeDiceFightT[2][1] :
sage.all.show(threeDiceFightT[0][0]," < ",threeDiceFightT[0][1]) # Red < Green
sage.all.show(threeDiceFightT[1][0]," > ",threeDiceFightT[1][1]) # Red > White
sage.all.show(threeDiceFightT[2][0]," < ",threeDiceFightT[2][1]) # Green < White
t=True
else :
t=False
return t
#below the test code in the second cell sagemath notebook: