In [1]:
import lib.operations as operations # basic variables concerning operations
from lib.schemas import * # related to the mathematical structure of the problem
from lib.textRepresentations import * # related to the propositions constituting the problem
from lib.subjectRepresentations import * # related to the problem state of a subject (representations and quantities)
from lib.paths import * # related to the solving process and its storing and analysis
from lib.dataManager import * # related to the final steps in the process gathering and printing results of simulation
Two schema describing the first relationships between the quantities are created
In [2]:
schema1=Schema("PoissonEF","PoissonEI",operations.addition,"PoissonGAIN","change")
schema2=Schema("ViandeEF","ViandeEI",operations.addition,"ViandeGAIN","change")
print(schema1.objects)
print(schema2.objects)
We then create the problem structure and add the schemas
In [3]:
struct=ProblemStructure()
struct.addSchema(schema1)
struct.addSchema(schema2)
struct.schemas
Out[3]:
And we create the schemas in order to create all the correspondances between the first two schemas
In [4]:
struct.addBridgingSchemas(schema1,schema2)
In [5]:
ls=struct.schemas
for schem in ls:
print(schem.objects)
We then update the field corresponding to set of the object in the problem
In [6]:
print(struct.objectSet)# before
struct.updateObjectSet()
print(struct.objectSet) #after
In [7]:
print(struct.objectSet)
We create a text object
In [15]:
text=Text()
And we add all the propositions, which are
In [16]:
t1='Au supermarché, le kilo de poisson a augmenté de 5 euros cette année'
t2='Un kilo de poisson coute maintenant 12 euros.'
t3='Au début de l\'année, le kilo de viande coutait le même prix que le kilo de poisson.'
t4='Le kilo de viande a augmenté de 3 euros de moins que le kilo de poisson'
q1=Representation(Quantity("PoissonGAIN","P1"),t1)
q2=Representation(Quantity("PoissonEF","T1"),t2)
q3=Representation(Quantity("PoissonEIminusViandeEI","dEI"),t3)
q4=Representation(Quantity("PoissonGAINminusViandeGAIN","d"),t4)
text.addTextInformation(TextInformation(q1))
text.addTextInformation(TextInformation(q2))
text.addTextInformation(TextInformation(q3))
text.addTextInformation(TextInformation(q4))
In [11]:
for info in text.textInformations:
q=info.representations[0].quantity
print(q.object, q.value)
In [12]:
text.setGoal(TextGoal(Goal('ViandeEF','Combien coute le kilo de viande maintenant?')))
In [17]:
t1='Au supermarché, le kilo de poisson était de 5 euros'
t2='Au supermarché, le kilo de poisson coute 5 euros'
t3='Un kilo de poisson était de 12 euros.'
t4='Au la fin de l\'année, le kilo de viande coute le même prix que le kilo de poisson.'
t5='Le kilo de viande a augmenté du même prix que le kilo de poisson.'
t6='Le kilo de viande a augmenté de 3 euros'
t7='Le kilo de viande a diminué de 3 euros'
t8='Le kilo de viande vaut 3 euros de moins que le kilo de poisson'
t9='Le kilo coute 3 euros à la fin'
a1=Representation(Quantity("PoissonEI","P1"),t1)
a2=Representation(Quantity("PoissonEF","P1"),t2)
a3=Representation(Quantity("PoissonEI","T1"),t3)
a4=Representation(Quantity("PoissonEFminusViandeEF","dEI"),t4)
a5=Representation(Quantity("PoissonGAINminusViandeGAIN","dEI"),t5)
a6=Representation(Quantity("ViandeGAIN","d"),t6)
a7=Representation(Quantity("ViandeGAIN","-d"),t7)
a8=Representation(Quantity("PoissonEFminusViandeEF","d"),t8)
a9=Representation(Quantity("ViandeEF","d"),t9)
text.getTextInformation(0).addAlternativeRepresentation(a1)
text.getTextInformation(0).addAlternativeRepresentation(a2)
text.getTextInformation(1).addAlternativeRepresentation(a3)
text.getTextInformation(2).addAlternativeRepresentation(a4)
text.getTextInformation(2).addAlternativeRepresentation(a5)
text.getTextInformation(3).addAlternativeRepresentation(a6)
text.getTextInformation(3).addAlternativeRepresentation(a7)
text.getTextInformation(3).addAlternativeRepresentation(a8)
text.getTextInformation(3).addAlternativeRepresentation(a9)
Let's inspect the different alternative representations pertaining to the fourth text proposition
In [116]:
textInfo=text.textInformations[3]
for representation in textInfo.representations:
print(representation.quantity.object,representation.quantity.value)
In [117]:
probleme1=Problem(struct,text)
Set the initial values
In [118]:
probleme1.setInitialValues({"P1":5,"T1":12,"dEI":0,"d":3,"-d":-3})
In [119]:
upD=Updater(probleme1) # create the problem state
upD.startAsUnderstood() # init the problem state, we start with expert representations
Updater has a central role in the program as it :
In [120]:
probState=upD.problemState
print "quantity dic: ", probState.quantitiesDic.dic
print "\n representations: ",probState.representations
In [121]:
c1=IntervalConstraint(['EF','EI'],operations.superiorOrEqualTo0)
This constraints implies that no negative values can be associated with object which has 'EI' or 'EF' as substring
In [122]:
c2=BehavioralConstraint(breakTheOldOne=True)
This constraints implies that if there is an alternative representation is selected, then the quantity formed by its prevous state is destroyed. In other terms, only one representation of the the same proposition is active at the same time.
In [123]:
constraints=[c1,c2]
In [124]:
solver1=Solver(upD,constraints)
In [125]:
solver1.updater.updateAppliableSchemas()
l=solver1.updater.appliableSchemaList
print(l)
print (l[0].objects)
In [126]:
move1=Move(l[0]) # a move is one level more abastract than schema or representation
stepInformations1=solver1.updater.applyMove(move1,solver1.constraints) # we can then use the function applyMove for schemas or representation
stepInformations is an instance of InfoStep (in subjectRepresentations.py) and contains many informations related to the concrete application of the move, and can be used to inspect precisely a solution path. Among others :
In [127]:
print(stepInformations1.formulaFirstPart,stepInformations1.valueToFind,stepInformations1.operands,stepInformations1.unknow)
In this specific case PoissonEI has been found knowing PoissonGAIN and PoissonEF. A new quantity is then now available :
In [128]:
solver1.updater.problemState.quantitiesDic.dic['PoissonEI']
Out[128]:
In [129]:
solver1.updater.updatePossibleRepresentationChange()
print len(solver1.updater.possibleRepresentationChangeList), "representations change are possible"
print solver1.updater.problemState.representations, " is the current representations state"
repChange=solver1.updater.possibleRepresentationChangeList[5]
print "\nindex of the proposition in the text", repChange.indexTextInformation
print "index of the alternative representation of this proposition", repChange.indexSelectedRepresentation
rep=solver1.updater.problem.text.textInformations[repChange.indexTextInformation].representations[repChange.indexSelectedRepresentation]
print(rep.quantity.object, rep.quantity.value)
In [130]:
move2=Move(repChange)
stepInformations2=solver1.updater.applyMove(move2,solver1.constraints)
print solver1.updater.problemState.representations, " is the new representations state"
Let's check that this new value is now in the quantitiesDic
In [131]:
solver1.updater.problemState.quantitiesDic.dic['ViandeGAIN']
Out[131]:
As we used the constraint c2=BehavioralConstraint(breakTheOldOne=True) we can see that the old representation of this text information is erased.
In [132]:
oldrep=solver1.updater.problem.text.textInformations[3].representations[0]
print "before : ",(oldrep.quantity.object, oldrep.quantity.value)
print "after : ", solver1.updater.problemState.quantitiesDic.dic[oldrep.quantity.object]
Four classes are involved to keep such record :
By convention the first step has for father the step with the id=0
In [133]:
step1=Step(move1,parentId=0, infos=stepInformations1,level=0)
step2=Step(move2,parentId=step1.sId, infos=stepInformations2, level=1) #we use the id of step1 to create step2
We can check if the problem is solved by the solved attribute
In [134]:
print "is the problem solved: ",step2.solved
Updater has no rollback feature for the moment, which means that
We can now add the step in the TreePaths
In [135]:
tp=TreePaths(solver1.updater) # or use the treePath instance tied to the solver : tp=solver1.TreePaths
tp.addStep(step1)
tp.addStep(step2)
TreePath allows many things :
In [136]:
id1=step1.childrenIds
id1
Out[136]:
In [137]:
tp.scanTree()
print(tp.treeOutput)
[Note] The last line gives a summary of what happenned. In this specific case we stopped the solving process without finding the solution. A more complex path would give such string :
T1-d : interpretation -> PoissonEF-(PoissonGAINminusViandeGAIN+PoissonEIminusViandeEI)=ViandeEF
This line is produced by the TreePath method trackBack which traceback the different paths and gives the last line. TrackBack is called in scanTree whenever a path is ended.
In [138]:
print(tp.trackBack(step2.sId))
trackBack is also usefull to store the different paths in lines which can be found in the pathList attribute of the updater.
In [139]:
firstPath=tp.pathList[0]
print(firstPath.formula)
print(firstPath.objectFormula)
print(firstPath.interpretationsSummary)
print(firstPath.valueFound)
print(firstPath.problemSolved)
We create a new solver from start
In [140]:
upD.startAsUnderstood()
autoSolver=Solver(upD,constraints)
Now, we give the pattern of actions the solver has to explore
In [141]:
l=[autoSolver.SOLVER]
autoSolver.generalSequentialSolver(listOfActions=l)
This is the simplest example, the instruction solver.SOLVER means that schemas will be applied until the solution is found. At each step, the research tree has as many branches as schemas which can be applied.
We can now check what gives treeOutput and pathList with the solver process
In [142]:
autoSolver.TreePaths.scanTree()
print(autoSolver.TreePaths.treeOutput)
In [143]:
print(str(autoSolver.TreePaths.pathsCount)+" different paths have been discovered" )
Let's inspect the first path recorded in the treePaths
In [144]:
aPath=autoSolver.TreePaths.pathList[0]
print(aPath.formula)
print(aPath.objectFormula)
print(aPath.interpretationsSummary)
print(aPath.valueFound)
print(aPath.problemSolved)
solver.SCHEMAS and solver.INTERP are two other instructions. For example if the list of actions is [solver.SCHEM,solver.INTERP,solver.SOLVE], then the automatic solver will start with applying a schema, then applying a interpretation change, and finally will finish by a solving process as seen above. This list of instruction will find all the paths which has this kind of pattern.
In [145]:
upD.startAsUnderstood()
autoSolver2=Solver(upD,constraints)
autoSolver2.generalSequentialSolver(listOfActions=[autoSolver2.SCHEMA,autoSolver2.INTERP,autoSolver2.SOLVER])
Let's inspect a path
In [146]:
autoSolver2.TreePaths.scanTree()
aPath=autoSolver2.TreePaths.pathList[43]
print(aPath.formula)
print(aPath.objectFormula)
print(aPath.interpretationsSummary)
print(aPath.valueFound)
print(aPath.problemSolved)
SimulatedDatas is a class used to store different treepath and eventually reduce some redondancies between the different paths.
In [147]:
simulatedDatas=SimulatedDatas()
simulatedDatas.addDataSet(solver1.TreePaths.pathList,"pbm1","Manual Solver")
simulatedDatas.addDataSet(autoSolver.TreePaths.pathList,"pbm1","Expert Solver")
simulatedDatas.addDataSet(autoSolver2.TreePaths.pathList,"pbm1","Another Solver")
simulatedDatas can print its datas in a CSV via simulatedDatas.printCSV() or in the console using simulatedDatas.printLines()
In [148]:
simulatedDatas.printLines()