Commits

Richard Shea committed fc7ecfa Draft

This set of changes resolves problems that previously occurred with determing
the correct question to ask next. Previously the 'weighted distribution' of
question asking (based upon previous successes and whether the question had
been asked at all previously) was not working as it should have.

A part of this release is the mechanism for expanding the set of potential
questions based upon successes to date is currently disabled. This will be
re-enabled in a future release.

  • Participants
  • Parent commits 54a1ed4

Comments (0)

Files changed (8)

File MathsMish/MMDBConstants.py

 class MMDBConstants:
     VALID_OPERATORS = ["+","x","-"]
     LHS_CANDIDATES = [1,2,3,4,5,6,7,8,9,10,11,12]
-    LHS_STARTOFFSET = 6
+    #LHS_STARTOFFSET = 6
+    LHS_STARTOFFSET = 7 
     LHS_THRESHOLD = 0.9
     RHS_CANDIDATES = [2,3,4,5,8,6,10,8,7,11,12]
+    #RHS_STARTOFFSET = 2
     RHS_STARTOFFSET = 2
     RHS_THRESHOLD = 0.4
     NEVERASKED_PROB = 0.5

File MathsMish/MMDBExceptions.py

 class MathsMishError(Exception): pass
 class NoAnswerError(MathsMishError): pass
 class NotInteger(MathsMishError): pass
+class NotTrueOrFalse(MathsMishError): pass
 class NotValidOperator(MathsMishError): pass
 class NotYetImplemented(MathsMishError): pass
 class FallingOutOfIfStatement(MathsMishError): pass

File MathsMish/QuestionMachine.py

         the 'candidate space' and 'question space' is 
         refreshed
         '''
-        myAttempt = Attempt(datetime.datetime.now(), myQuestion.sum.lhs, myQuestion.sum.rhs, myQuestion.sum.operator, None, self.userid, proposedAnswer)
+        myAttempt = Attempt(datetime.datetime.now(), myQuestion.sum.lhs, myQuestion.sum.rhs, myQuestion.sum.operator, None, self.userid, proposedAnswer, completed=True)
         AttemptManager.Insert(myAttempt)
         self.__maintainCandidateAndQuestionSpace()
 
 
     def __maintainCandidateAndQuestionSpace(self):
 
-        self.__QuestionPool = [] 
-        self.__lstAskedMostRecentlyFailed = []
-        self.__lstAskedMostRecentlySucceeded = []
-        self.__lstNeverAsked = []
+        self.QuestionPool = [] 
+        self.lstAskedMostRecentlyFailed = []
+        self.lstAskedMostRecentlySucceeded = []
+        self.lstNeverAsked = []
 
         self.CandidateSpace = self.__buildCandidateSpace()
 
         #Create 'base level' operand lists based upon hardcoded defaults
         self.__addToCandidateSpaceFromDefaults()
         #... now add extra operands based upon past successful answers
-        self.__addToCandidateSpaceBasedUponPastSuccesses()
+
+        #Temporarily remove this while concentrating on the process of feeding
+        #the optimal next question
+        #self.__addToCandidateSpaceBasedUponPastSuccesses()
 
         #Using the lhs/rhs operand candidates we have found build a set of questions
 
                 lq.append(Question(lhs, rhs, self.__operator))
 
         #... now add extra operands based upon past successful answers
-        self.__addToCandidateSpaceBasedUponPastSuccessesNew(lq)
+        #Temporarily remove this while concentrating on the process of feeding
+        #the optimal next question
+        #self.__addToCandidateSpaceBasedUponPastSuccessesNew(lq)
 
         #Ensure all Sums in the proposed space are in the database
         #if not add them in
         mostRecentlyFailedThresholdRange = (mostRecentlySucceededThreshold, MMDBConstants.NEVERASKED_PROB + MMDBConstants.MOSTRECENTOK_PROB + MMDBConstants.MOSTRECENTNOTOK_PROB)
 
         #Establish lengths of lists     
-        lenNeverAsked = len(self.__lstNeverAsked)
-        lenMostRecentSucceeded = len(self.__lstAskedMostRecentlySucceeded)
-        lenMostRecentFailed = len(self.__lstAskedMostRecentlyFailed)
+        lenNeverAsked = len(self.lstNeverAsked)
+        lenMostRecentSucceeded = len(self.lstAskedMostRecentlySucceeded)
+        lenMostRecentFailed = len(self.lstAskedMostRecentlyFailed)
 
         #Adjust the cumulative probablities if we have no 
-        if len(self.__lstNeverAsked) == 0:
+        if len(self.lstNeverAsked) == 0:
             raise MathsMishError
 
         if ((lenMostRecentSucceeded > 0) & (lenMostRecentFailed > 0)):
                 neverAskedThreshold = mostRecentlyFailedThreshold
 
 
-            if len(self.__lstAskedMostRecentlySucceeded) == 0:
+            if len(self.lstAskedMostRecentlySucceeded) == 0:
                 neverAskedThreshold = mostRecentlySucceededThreshold
-            if len(self.__lstAskedMostRecentlyFailed) == 0:
+            if len(self.lstAskedMostRecentlyFailed) == 0:
                 neverAskedThreshold = mostRecentlyFailedThreshold
 
 
-        if len(self.__lstNeverAsked) == 0:
+        if len(self.lstNeverAsked) == 0:
             raise MMDBExceptions.MathsMishError
         '''
         
             questionSelector = random.random()
             try:
                 if questionSelector < neverAskedThreshold:
-                    return random.choice(self.__lstNeverAsked)
+                    return random.choice(self.lstNeverAsked)
                 elif questionSelector < mostRecentlySucceededThreshold:
-                    return random.choice(self.__lstAskedMostRecentlySucceeded)
+                    return random.choice(self.lstAskedMostRecentlySucceeded)
                 elif questionSelector < mostRecentlyFailedThreshold:
-                    return random.choice(self.__lstAskedMostRecentlyFailed)
+                    return random.choice(self.lstAskedMostRecentlyFailed)
                 else:
                     raise MMDBExceptions.FallingOutOfIfStatement 
             except IndexError:
             #Q = Question(summAttRow[2], summAttRow[3], summAttRow[1])
             #Q = Question(summAttRow.question.lhs, summAttRow.question.rhs, summAttRow.question.operator)
             myQuestion = myAttempt.question
-            self.__QuestionPool.append(myQuestion)
-            if (myAttempt.when == None) or (myAttempt.question.hasBeenAnswered() == False):
-                self.__lstNeverAsked.append(myQuestion)
+            self.QuestionPool.append(myQuestion)
+            if (myAttempt.when == None) or (myAttempt.question.completed == False):
+                self.lstNeverAsked.append(myQuestion)
             else:
-                if myAttempt.question.goodAnswer() == True:
-                    self.__lstAskedMostRecentlySucceeded.append(myQuestion)
-                elif myAttempt.question.goodAnswer() == False: 
-                    self.__lstAskedMostRecentlyFailed.append(myQuestion)
+                if myAttempt.correctAnswer == True:
+                    self.lstAskedMostRecentlySucceeded.append(myQuestion)
+                elif myAttempt.correctAnswer == False: 
+                    self.lstAskedMostRecentlyFailed.append(myQuestion)
                 else:
                     raise MMDBExceptions.FallingOutOfIfStatement 
 
         self.__printPoolDiagnostics()
 
     def __printPoolDiagnostics(self):
-        print "self.__QuestionPool = %s" % ( len(self.__QuestionPool))
-        print "self.__lstAskedMostRecentlyFailed =%s" % len(self.__lstAskedMostRecentlyFailed)
-        print "self.__lstAskedMostRecentlySucceeded =%s" % len(self.__lstAskedMostRecentlySucceeded) 
-        print "self.__lstNeverAsked = %s" % (len(self.__lstNeverAsked))
-        self.__module_logger.debug("self.__QuestionPool = %s" % ( len(self.__QuestionPool)))
-        self.__module_logger.debug("self.__lstAskedMostRecentlyFailed = %s" % len(self.__lstAskedMostRecentlyFailed))
-        self.__module_logger.debug("self.__lstAskedMostRecentlySucceeded = %s" % len(self.__lstAskedMostRecentlySucceeded)) 
-        self.__module_logger.debug("self.__lstNeverAsked = %s" % (len(self.__lstNeverAsked)))
+        print "self.QuestionPool = %s" % ( len(self.QuestionPool))
+        print "self.lstAskedMostRecentlyFailed =%s" % len(self.lstAskedMostRecentlyFailed)
+        print "self.lstAskedMostRecentlySucceeded =%s" % len(self.lstAskedMostRecentlySucceeded) 
+        print "self.lstNeverAsked = %s" % (len(self.lstNeverAsked))
+        self.__module_logger.debug("self.QuestionPool = %s" % ( len(self.QuestionPool)))
+        self.__module_logger.debug("self.lstAskedMostRecentlyFailed = %s" % len(self.lstAskedMostRecentlyFailed))
+        self.__module_logger.debug("self.lstAskedMostRecentlySucceeded = %s" % len(self.lstAskedMostRecentlySucceeded)) 
+        self.__module_logger.debug("self.lstNeverAsked = %s" % (len(self.lstNeverAsked)))
         self.__module_logger.debug("self.__lhsDefaultsInUse = %s" % (self.__lhsDefaultsInUse))
         self.__module_logger.debug("self.__rhsDefaultsInUse = %s" % (self.__rhsDefaultsInUse))
 

File MathsMish/mmdb/BusinessObject/Attempt.py

 from MathsMish.mmdb.BusinessObject.Player import Player 
 from MathsMish.mmdb.BusinessObject.Sum import Sum 
 class Attempt(object):
-    def __init__(self, whn = None, lhs = None, rhs = None, op = None, correct = None, uid = None, suppAns = None):
+    def __init__(self, whn = None, lhs = None, rhs = None, op = None, correct = None, uid = None, suppAns = None, completed = None):
         self._player = Player(uid)
-        self._question = Question(lhs, rhs, op, suppliedAnswer= suppAns)
+        self._question = Question(lhs, rhs, op, suppliedAnswer = suppAns, completed = completed)
         self._when = whn 
-        self._correct = None 
+        self._correct = correct
 
     def getsum(self):
         return self._question
     when = property(getwhen, setwhen, "I'm the 'when' property.")
 
     def getcorrect(self):
-        return self.question.calculateAnswer()
+        return self._correct
+        #return self.question.calculateAnswer()
 
     correctAnswer = property(getcorrect, None, "I'm the 'correct' property.")
     

File MathsMish/mmdb/BusinessObject/Player.py

         self._username = username 
         self._fullname = fullname 
 
+    def __repr__(self):
+        return "Player(id = %s, username = %s, fullname = %s)" % (self._id, self._username, self._fullname)
+
     def getid(self):
         return self._id
     def setid(self, value):

File MathsMish/mmdb/BusinessObject/Question.py

 from MathsMish.MMDBConstants import MMDBConstants
 from MathsMish.mmdb.BusinessObject.Sum import Sum 
 class Question(object):
-    def __init__(self, lhs, rhs, operator, inuse = None, order = None, userid = None, suppliedAnswer = None):
+    def __init__(self, lhs, rhs, operator, completed = False, inuse = None, order = None, userid = None, suppliedAnswer = None):
         if operator == "*":
             operator = "x"
-        self.__validateInitArgs(lhs, rhs, operator)
+
+        self.__validateInitArgs(lhs, rhs, operator, completed)
     
         self.__sum = Sum(lhs, rhs, operator)
         self.__inuse = inuse 
         self.__order = order 
         self.__userid = userid 
         self.__suppliedAnswer = suppliedAnswer 
+        self.__completed = completed
     
     def __str__(self):
         return "%s %s %s" % (self.sum.lhs, self.sum.operator, self.sum.rhs)
 
+    def __repr__(self):
+        return "Question(lhs=%s,rhs=%s,operator=%s)" % (self.sum.lhs, self.sum.rhs, self.sum.operator)
+
     def getsum(self):
         return self.__sum
 
 
     suppliedAnswer = property(getSuppliedAnswer, setSuppliedAnswer, "I'm the 'SuppliedAnswer' property.")   
 
+    def getCompleted(self):
+        return self.__completed
+
+    def setCompleted(self, value):
+        self.__completed = value
+
+    completed = property(getCompleted, setCompleted, "I'm the 'Completed' property.")   
 
     def getinuse(self):
         return self.__inuse
         else:
             return True
     
-    def __validateInitArgs(self, lhs, rhs, operator):
+    def __validateInitArgs(self, lhs, rhs, operator, completed):
         try:
                 operand = int(lhs)
         except ValueError:
         try:
                 operand = int(rhs)
         except ValueError:
-                raise MMDBExceptions.NotInteger("RHS parameter is not an integer")
+                raise MathsMish.MMDBExceptions.NotInteger("RHS parameter is not an integer")
         except TypeError:
-                raise MMDBExceptions.NotInteger("RHS parameter is not an integer")
+                raise MathsMish.MMDBExceptions.NotInteger("RHS parameter is not an integer")
 
         if operator not in MMDBConstants.VALID_OPERATORS:
-                raise MMDBExceptions.NotValidOperator
+                raise MathsMish.MMDBExceptions.NotValidOperator
+
+        if completed not in [True, False]:
+                raise MathsMish.MMDBExceptions.NotTrueOrFalse

File MathsMish/mmdb/BusinessObject/Sum.py

         self._lhs = lhs 
         self._rhs = rhs 
         self._operator = operator 
-        self.__id =  id
+        self._id =  id
     
     def __str__(self):
         return "%s %s %s" % (self.lhs, self.operator, self.rhs)
+
+    def __repr__(self):
+        return "Sum(lhs=%s,rhs=%s,operator=%s)" % (self._lhs, self._rhs, self._operator)
     
 
     def getlhs(self):

File MathsMish/mmdb/DataAccess/AttemptDB.py

 
     @staticmethod
     def __GetCountsSuccessesForUserAndSpecifiedOperand(user, lstOperands, operandType):
-        #import pdb; pdb.set_trace()
         if operandType == Operand.RightHandSide:
             sql = SELECTATTWHENMOSTRECENTRESULTSUCCESSFULRHS
         elif operandType == Operand.LeftHandSide:
                 blnCorrect = False              
             else:
                 raise MMDBExceptions.FallingOutOfIfStatement                
-            lstAttempts.append(Attempt(row['ATT_TIMESTAMP'], row['SUM_LHS'], row['SUM_RHS'], opAsString, blnCorrect))
+
+            blnCompleted = None
+            if row['ATT_COMPLETED'] == SQLLITETRUE:
+                blnCompleted = True
+            elif row['ATT_COMPLETED'] == SQLLITEFALSE:
+                blnCompleted = False
+            elif row['ATT_COMPLETED'] == None:
+                blnCompleted = False              
+            else:
+                raise MMDBExceptions.FallingOutOfIfStatement                
+            lstAttempts.append(Attempt(row['ATT_TIMESTAMP'], row['SUM_LHS'], row['SUM_RHS'], opAsString, blnCorrect, completed=blnCompleted))
         return lstAttempts