def getAllStudentNodeKeysList(): graph = connectToGraph() studentNodes = graph.data("MATCH (node:Student) RETURN node.key") studentNodesList = [] count = 0 while count < len(studentNodes): studentNodesList.append(studentNodes[count]['node.key']) count = count + 1 return studentNodesList
def getTotalNoOfTeacherNodes(): graph = connectToGraph() studentNodes = graph.data("MATCH (node:Teacher) RETURN node.key") return len(studentNodes)
def markStudBFSLogicGateAnswer(): # Connect to Graph graph = connectToGraph() answerDiagramCorrect = 'false' teacherInputNodes = graph.data( "MATCH (node:Teacher) WHERE node.symbol='input' RETURN node") studentInputNodes = graph.data( "MATCH (node:Student) WHERE node.symbol='input' RETURN node") teacherQueue = [teacherInputNodes[0]['node']['key']] count = 0 while count < len(studentInputNodes): if studentInputNodes[count]['node']['text'] == teacherInputNodes[0][ 'node']['text']: studentQueue = [studentInputNodes[count]['node']['key']] count = count + 1 count = 1 while count < len(teacherInputNodes): teacherQueue.insert(0, teacherInputNodes[count]['node']['key']) studCount = 0 while studCount < len(studentInputNodes): if studentInputNodes[studCount]['node'][ 'text'] == teacherInputNodes[count]['node']['text']: studentQueue.insert( 0, studentInputNodes[studCount]['node']['key']) studCount = studCount + 1 count = count + 1 childlessTeacherOtherParents = [] childHavingTeacherOtherParents = [] childlessStudentOtherParents = [] childHavingStudentOtherParents = [] # maintains all matched and completed nodes so far(the ones which have been removed from the queue after completion) matchedCompletedTeacherNodes = [] matchedCompletedStudentNodes = [] # each time a student gate is visited, it is added to this visitedStudentNodes = [] matchedTeacherLevelNodes = [] matchedStudentLevelNodes = [] additionalNodes = [] deletedNodes = [] substitutedNodes = [] addOrSubNodes = [] delOrSubNodes = [] errorneousTeacherNodes = [] errorneousStudentNodes = [] totNoOfAdditionalNodes = 0 totNoOfDeletedNodes = 0 totNoOfSubstitutedNodes = 0 totNoOfOtherIncorrectNodes = 0 feedback = "" # maintains parents to see if all its children has been traversed before and so that it can be removed from the queue # traversedChildMatchFoundNodes = [] while teacherQueue and studentQueue: # or teacherCurrent = teacherQueue.pop() studentCurrent = studentQueue.pop() currentTeacherNodeInfo = graph.data( "MATCH (node:Teacher) WHERE node.key= {key} RETURN node", parameters={"key": teacherCurrent}) currentStudentNodeInfo = graph.data( "MATCH (node:Student) WHERE node.key= {key} RETURN node", parameters={"key": studentCurrent}) if currentTeacherNodeInfo[0]['node']['symbol'] == "output": if currentStudentNodeInfo[0]['node']['symbol'] == "output": feedback = feedback + 'The output and the connections to it are correct. ' answerDiagramCorrect = 'true' break teacherChildNodes = graph.data( "MATCH (parent:Teacher)-[:TO]->(child:Teacher) WHERE parent.key= {key} RETURN child", parameters={"key": teacherCurrent}) studentChildNodes = graph.data( "MATCH (parent:Student)-[:TO]->(child:Student) WHERE parent.key= {key} RETURN child", parameters={"key": studentCurrent}) for teacherChild in teacherChildNodes: # get all parents of current teacher child node under analysis except the current teacher parent node teacherChildParents = graph.data( "MATCH (parent:Teacher)-[:TO]->(child:Teacher) WHERE child.key= {key} AND parent.key <> {parentKey} RETURN parent", parameters={ "key": teacherChild['child']['key'], "parentKey": teacherCurrent }) teacherChildParentsList = list(teacherChildParents) childlessTeacherOtherParents = [] childHavingTeacherOtherParents = [] for teacherChildParent in teacherChildParentsList: teacherChildParentChildrenNodes = graph.data( "MATCH (parent:Teacher)-[:TO]->(child:Teacher) WHERE parent.key= {parentKey} AND child.key <> {childKey} RETURN child", parameters={ "parentKey": teacherChildParent['parent']['key'], "childKey": teacherChild['child']['key'] }) # check whether other teacher parents have other children besides current child if not teacherChildParentChildrenNodes: childlessTeacherOtherParents.append(teacherChildParent) else: childHavingTeacherOtherParents.append(teacherChildParent) for studentChild in studentChildNodes: if currentTeacherNodeInfo[0]['node']['symbol'] == currentStudentNodeInfo[0]['node']['symbol'] and \ teacherChild['child']['symbol'] == studentChild['child']['symbol']: studentChildParents = graph.data( "MATCH (parent:Student)-[:TO]->(child:Student) WHERE child.key= {key} AND parent.key <> {parentKey} RETURN parent", parameters={ "key": studentChild['child']['key'], "parentKey": studentCurrent }) studentChildParentsList = list(studentChildParents) childlessStudentOtherParents = [] childHavingStudentOtherParents = [] for studentChildParent in studentChildParentsList: studentChildParentChildrenNodes = graph.data( "MATCH (parent:Student)-[:TO]->(child:Student) WHERE parent.key= {parentKey} AND child.key <> {childKey} RETURN child", parameters={ "parentKey": studentChildParent['parent']['key'], "childKey": studentChild['child']['key'] }) # check whether other student parents have other children besides current child if not studentChildParentChildrenNodes: childlessStudentOtherParents.append( studentChildParent) else: childHavingStudentOtherParents.append( studentChildParent) if len(childlessTeacherOtherParents) == len(childlessStudentOtherParents) and \ len(childHavingTeacherOtherParents) == len(childHavingStudentOtherParents): if currentStudentNodeInfo[0]['node'][ 'symbol'] == "input" and not currentStudentNodeInfo[ 0]['node'][ 'key'] in matchedCompletedStudentNodes: matchedCompletedTeacherNodes.append(teacherCurrent) matchedCompletedStudentNodes.append(studentCurrent) childlessStudentOtherParentsNotInQueue = [] # if this gate has been visited once, then already childless other parents have been removed if they were in the queue # so no need to do it again and it cannot be done if not studentChild['child'][ 'key'] in visitedStudentNodes: # remove childless other teacher parents and remove childless other student parents for childlessTeacherNode in childlessTeacherOtherParents: for childlessStudentNode in childlessStudentOtherParents: if childlessTeacherNode['parent'][ 'symbol'] == childlessStudentNode[ 'parent']['symbol']: if childlessTeacherNode['parent']['key'] in teacherQueue and\ childlessStudentNode['parent']['key'] in studentQueue: teacherQueue.remove( childlessTeacherNode['parent'] ['key']) studentQueue.remove( childlessStudentNode['parent'] ['key']) if childlessStudentNode['parent'][ 'symbol'] == "input" and not childlessStudentNode[ 'parent'][ 'key'] in matchedCompletedStudentNodes: matchedCompletedTeacherNodes.append( childlessTeacherNode[ 'parent']['key']) matchedCompletedStudentNodes.append( childlessStudentNode[ 'parent']['key']) visitedStudentNodes.append( studentChild['child']['key']) else: childlessStudentOtherParentsNotInQueue.append( childlessStudentNode['parent'] ['key']) visitedStudentNodes.append( studentChild['child']['key']) # insert matched gate to queue if len(childlessStudentOtherParentsNotInQueue) == 0 and \ visitedStudentNodes.count(studentChild['child']['key']) == (len(studentChildParents) + 1): teacherQueue.insert(0, teacherChild['child']['key']) studentQueue.insert(0, studentChild['child']['key']) if not studentChild['child'][ 'symbol'] == 'output': # and not studentChild['child']['key'] in matchedCompletedStudentNodes feedback = feedback + 'The gate: ' + studentChild[ 'child']['symbol'].upper( ) + ' and its input connections are correct. ' matchedCompletedTeacherNodes.append( teacherChild['child']['key']) matchedCompletedStudentNodes.append( studentChild['child']['key']) if len(teacherChildNodes) == len( studentChildNodes ) or len(teacherChildNodes) > len(studentChildNodes): matchedTeacherLevelNodes.append( teacherChild['child']['key']) elif len(teacherChildNodes) < len(studentChildNodes): matchedStudentLevelNodes.append( studentChild['child']['key']) childlessTeacherOtherParents = [] childlessStudentOtherParents = [] childHavingTeacherOtherParents = [] childHavingStudentOtherParents = [] childlessStudentOtherParentsNotInQueue = [] break if len(teacherChildNodes) == len(studentChildNodes): if not len(teacherChildNodes) == len(matchedTeacherLevelNodes): for teacherChild in teacherChildNodes: if not teacherChild['child'][ 'key'] in matchedTeacherLevelNodes and not teacherChild[ 'child']['key'] in errorneousTeacherNodes: substitutedNodes.append(teacherChild['child']['key']) totNoOfSubstitutedNodes = totNoOfSubstitutedNodes + 1 errorneousTeacherNodes.append( teacherChild['child']['key']) for studentChild in studentChildNodes: if not studentChild['child'][ 'key'] in matchedStudentLevelNodes: errorneousStudentNodes.append( studentChild['child']['key']) elif len(teacherChildNodes) > len(studentChildNodes): if len(matchedTeacherLevelNodes) < len(studentChildNodes): for teacherChild in teacherChildNodes: if not teacherChild['child'][ 'key'] in matchedTeacherLevelNodes and not teacherChild[ 'child']['key'] in errorneousTeacherNodes: delOrSubNodes.append(teacherChild['child']['key']) totNoOfOtherIncorrectNodes = totNoOfOtherIncorrectNodes + 1 errorneousTeacherNodes.append( teacherChild['child']['key']) elif len(matchedTeacherLevelNodes) == len(studentChildNodes): for teacherChild in teacherChildNodes: if not teacherChild['child'][ 'key'] in matchedTeacherLevelNodes and not teacherChild[ 'child']['key'] in errorneousTeacherNodes: deletedNodes.append(teacherChild['child']['key']) totNoOfDeletedNodes = totNoOfDeletedNodes + 1 errorneousTeacherNodes.append( teacherChild['child']['key']) for studentChild in studentChildNodes: if not studentChild['child']['key'] in matchedStudentLevelNodes: errorneousStudentNodes.append(studentChild['child']['key']) elif len(teacherChildNodes) < len(studentChildNodes): if len(matchedStudentLevelNodes) == len(teacherChildNodes): for studentChild in studentChildNodes: if not studentChild['child'][ 'key'] in matchedStudentLevelNodes and not studentChild[ 'child']['key'] in errorneousStudentNodes: additionalNodes.append(studentChild['child']['key']) totNoOfAdditionalNodes = totNoOfAdditionalNodes + 1 errorneousStudentNodes.append( studentChild['child']['key']) elif len(matchedStudentLevelNodes) < len(teacherChildNodes): for studentChild in studentChildNodes: if not studentChild['child'][ 'key'] in matchedStudentLevelNodes and not studentChild[ 'child']['key'] in errorneousStudentNodes: addOrSubNodes.append(studentChild['child']['key']) totNoOfOtherIncorrectNodes = totNoOfOtherIncorrectNodes + 1 errorneousStudentNodes.append( studentChild['child']['key']) for teacherChild in teacherChildNodes: if not teacherChild['child']['key'] in matchedTeacherLevelNodes: errorneousTeacherNodes.append(teacherChild['child']['key']) matchedTeacherLevelNodes = [] matchedStudentLevelNodes = [] # handles additional nodes down an additional node starting path if additionalNodes: totNoOfAdditionalNodes = detectUndetectedGates( "additionalNodes", graph, additionalNodes, matchedCompletedStudentNodes, totNoOfAdditionalNodes) # handles deleted nodes down a deleted node starting path if deletedNodes: totNoOfDeletedNodes = detectUndetectedGates( "deletedNodes", graph, deletedNodes, matchedCompletedTeacherNodes, totNoOfDeletedNodes) # handles substituted nodes down a substituted node starting path if substitutedNodes: totNoOfSubstitutedNodes = detectUndetectedGates( "substitutedNodes", graph, substitutedNodes, matchedCompletedTeacherNodes, totNoOfSubstitutedNodes) # handles additional/substituted nodes down a additional/substituted node starting path if addOrSubNodes: totNoOfOtherIncorrectNodes = detectUndetectedGates( "addOrSubNodes", graph, addOrSubNodes, matchedCompletedStudentNodes, totNoOfOtherIncorrectNodes) # handles deleted/substituted nodes down a deleted/substituted node starting path if delOrSubNodes: totNoOfOtherIncorrectNodes = detectUndetectedGates( "delOrSubNodes", graph, delOrSubNodes, matchedCompletedTeacherNodes, totNoOfOtherIncorrectNodes) if totNoOfAdditionalNodes == 0 and totNoOfDeletedNodes == 0 and totNoOfSubstitutedNodes == 0 and \ totNoOfOtherIncorrectNodes == 0: feedback = feedback + "Excellent Job! All the inputs, gates, output, and the connections are correct! " feedback = feedback + "Please refer your answer diagram for feedback on where you went wrong. Green " +\ "indicates correct gates and connections while Red indicates wrong gates and connections. " +\ "Please note that any input(to a gate) connected to a wrong gate(a gate wbich has wrong " +\ "connections even if the symbol is the same) is identified wrong by the system and in the highlighted gate feedback. " return matchedCompletedStudentNodes, totNoOfAdditionalNodes, totNoOfDeletedNodes, \ totNoOfSubstitutedNodes, totNoOfOtherIncorrectNodes, feedback, answerDiagramCorrect
def simulateLogicGate(diagramBelongsTo, noOfInputs, logicGateQuestionId): # Connect to Graph graph = connectToGraph() # noOfInputs = resultSet[0] binaryCombinationList = list(itertools.product([0, 1], repeat=noOfInputs)) queue = [] inputsProcessedOrder = '' noOfMatchedCombinations = 0 bddNodeKey = 1 inputNodes = graph.data( "MATCH (node:%s) WHERE node.symbol='input' RETURN node" % diagramBelongsTo) if diagramBelongsTo == "Teacher": count = 0 while count < len(inputNodes): queue.insert(0, inputNodes[count]['node']['key']) count = count + 1 elif diagramBelongsTo == "Student": connection = connectToMySQL() cur = connection.cursor() cur.execute( "SELECT inputProcessedOrder FROM logic_gate_question WHERE logicgateqId = %s", (logicGateQuestionId)) resultSet = cur.fetchone() cur.close() connection.close() inputsProcessedOrder = resultSet[0] combinationLoopCount = 0 while combinationLoopCount < len(binaryCombinationList): inputsProcessedCount = 0 currentCombination = binaryCombinationList[combinationLoopCount] if diagramBelongsTo == "Student" or (combinationLoopCount >= 1 and diagramBelongsTo == "Teacher"): inputs = inputsProcessedOrder.split(',') for input in inputs: count = 0 while count < len(inputNodes): if inputNodes[count]['node']['text'] == input: queue.insert(0, inputNodes[count]['node']['key']) break count = count + 1 while queue: currentNode = queue.pop() currentNodeInfo = graph.data( "MATCH (node:%s) WHERE node.key= {key} RETURN node" % diagramBelongsTo, parameters={"key": currentNode}) currentChildNodes = graph.data( "MATCH (parent:%s)-[:TO]->(child:%s) WHERE parent.key= {key} RETURN child" % (diagramBelongsTo, diagramBelongsTo), parameters={"key": currentNode}) if currentNodeInfo[0]['node'][ 'symbol'] == "input" and combinationLoopCount == 0 and diagramBelongsTo == "Teacher": inputsProcessedOrder = inputsProcessedOrder + currentNodeInfo[ 0]['node']['text'] + "," if currentNodeInfo[0]['node']['symbol'] == "input": currentInput = currentCombination[inputsProcessedCount] inputsProcessedCount = inputsProcessedCount + 1 if currentNodeInfo[0]['node']['symbol'] == "output": if combinationLoopCount == 0 and diagramBelongsTo == "Teacher": inputsProcessedOrder = inputsProcessedOrder[:-1] output = currentNodeInfo[0]['node']['inputs'] graph.run("MATCH (node:%s) REMOVE node.inputs" % diagramBelongsTo) if diagramBelongsTo == "Teacher": connection = connectToMySQL() cur = connection.cursor() if noOfInputs == 1: cur.execute( "INSERT INTO simulate_logicgate(inputOne, output) VALUES('%s', '%s')", (currentCombination[0], output[0])) elif noOfInputs == 2: cur.execute( "INSERT INTO simulate_logicgate(inputOne, inputTwo, output) VALUES('%s', '%s', '%s')", (currentCombination[0], currentCombination[1], output[0])) elif noOfInputs == 3: cur.execute( "INSERT INTO simulate_logicgate(inputOne, inputTwo, inputThree, output) VALUES('%s', '%s', '%s', '%s')", (currentCombination[0], currentCombination[1], currentCombination[2], output[0])) cur.close() connection.close() elif diagramBelongsTo == "Student": connection = connectToMySQL() cur = connection.cursor() if noOfInputs == 1: cur.execute( "SELECT output FROM simulate_logicgate WHERE inputOne = '%s'", (currentCombination[0])) elif noOfInputs == 2: cur.execute( "SELECT output FROM simulate_logicgate WHERE inputOne = '%s' AND inputTwo = '%s'", (currentCombination[0], currentCombination[1])) elif noOfInputs == 3: cur.execute( "SELECT output FROM simulate_logicgate WHERE inputOne = '%s' AND inputTwo = '%s' AND inputThree = '%s'", (currentCombination[0], currentCombination[1], currentCombination[2])) resultSet = cur.fetchone() cur.close() connection.close() if resultSet[0] == output[0]: noOfMatchedCombinations = noOfMatchedCombinations + 1 for childNode in currentChildNodes: childParents = graph.data( "MATCH (parent:%s)-[:TO]->(child:%s) WHERE child.key= {key} RETURN parent" % (diagramBelongsTo, diagramBelongsTo), parameters={"key": childNode['child']['key']}) childNodeDetails = Node(diagramBelongsTo, key=childNode['child']['key']) graph.merge(childNodeDetails) if currentNodeInfo[0]['node']['symbol'] == "input": handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "and": currentInput = getInputForAndOrNandNor( currentNodeInfo, 1, 0, 0) handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "or": currentInput = getInputForAndOrNandNor( currentNodeInfo, 0, 1, 1) handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "not": inputs = currentNodeInfo[0]['node']['inputs'] if inputs[0] == 0: currentInput = 1 else: currentInput = 0 handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "nand": currentInput = getInputForAndOrNandNor( currentNodeInfo, 0, 0, 1) handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "nor": currentInput = getInputForAndOrNandNor( currentNodeInfo, 1, 1, 0) handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "xor": currentInput = getInputForXorXnor(currentNodeInfo, 0, 1) handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) elif currentNodeInfo[0]['node']['symbol'] == "xnor": currentInput = getInputForXorXnor(currentNodeInfo, 1, 0) handleGateInputsAndQueue(childNode, childNodeDetails, currentInput, childParents, queue) childNodeDetails.push() if diagramBelongsTo == "Teacher": connection = connectToMySQL() cur = connection.cursor() cur.execute( "UPDATE logic_gate_question SET inputProcessedOrder = %s WHERE logicgateqId = %s", (inputsProcessedOrder, logicGateQuestionId)) cur.close() connection.close() combinationLoopCount = combinationLoopCount + 1 return noOfMatchedCombinations
def markStudDFSBlockAnswer(processQuestionId, studentAnswerId): # Connect to Graph graph = connectToGraph() whiteSpaceTokenizer = py_stringmatching.WhitespaceTokenizer( return_set=True) jaccard = py_stringmatching.Jaccard() levenshtein = py_stringmatching.Levenshtein() teacherStartNodeKey = graph.data( "MATCH (node:Teacher) WHERE node.text='start' RETURN node.key") studentStartNodeKey = graph.data( "MATCH (node:Student) WHERE node.text='start' RETURN node.key") teachStack = [teacherStartNodeKey[0]['node.key']] studStack = [studentStartNodeKey[0]['node.key']] teachVisitedNodes = [] studVisitedNodes = [] # keeps track of the nodes matched in each level matchedTeacherNodes = [] matchedStudentNodes = [] notMatchedParentTeacherNodes = [] # keeps track of all the nodes visited throughout graph traversal and a node is added to this each time it is visited allMatchedTeachNodes = [] allMatchedStudNodes = [] additionalNodes = [] deletedNodes = [] substitutedNodes = [] addOrSubNodes = [] delOrSubNodes = [] totNoOfAdditionalNodes = 0 totNoOfDeletedNodes = 0 totNoOfSubstitutedNodes = 0 totNoOfOtherIncorrectNodes = 0 totNoOfOtherSubstitutedNodes = 0 totNoOfMatchedNodes = 0 feedback = "" while teachStack or studStack: if teachStack and studStack: teachCurrent = teachStack.pop() studCurrent = studStack.pop() teacherCurrentText = graph.data( "MATCH (node:Teacher) WHERE node.key= {key} RETURN node.text", parameters={"key": teachCurrent}) studentCurrentText = graph.data( "MATCH (node:Student) WHERE node.key= {key} RETURN node.text", parameters={"key": studCurrent}) teacherChildNodes = graph.data( "MATCH (parent:Teacher)-[:TO]->(child:Teacher) WHERE parent.key= {key} RETURN child", parameters={"key": teachCurrent}) #teacherStartNodeKey[0]['node.key'] studentChildNodes = graph.data( "MATCH (parent:Student)-[:TO]->(child:Student) WHERE parent.key= {key} RETURN child", parameters={"key": studCurrent}) #studentStartNodeKey[0]['node.key'] teachChildNodesList = list(teacherChildNodes) studChildNodesList = list(studentChildNodes) for teacherChild in teachChildNodesList: teachText = teacherChild['child']['text'] # teachTextTokens = whiteSpaceTokenizer.tokenize(teacherChild['child']['text']) print(teachText) matchFound = 'false' for studentChild in studChildNodesList: if not studentChild['child']['key'] in matchedStudentNodes: print('current stud child') print(studentChild['child']['text']) childText = studentChild['child']['text'] synsetSim_score = getPhraseSimilarity( teachText, childText) if re.match(teachText, childText, re.IGNORECASE) or synsetSim_score >= 0.55: print( 'threshold similarity added to Student stack') feedback = feedback + 'The block:' + studentChild['child']['text'] + \ ' connected to block:' + studentCurrentText[0]['node.text'] + ' is correct. ' matchFound = 'true' if not teacherChild['child'][ 'key'] in teachVisitedNodes: studStack.append(studentChild['child']['key']) teachStack.append(teacherChild['child']['key']) if not studentChild['child'][ 'key'] in allMatchedStudNodes and not studentChild[ 'child']['text'] == 'end': totNoOfMatchedNodes = totNoOfMatchedNodes + 1 allMatchedTeachNodes.append( teacherChild['child']['key']) allMatchedStudNodes.append( studentChild['child']['key']) if len(teachChildNodesList) > len( studChildNodesList): matchedTeacherNodes.append( teacherChild['child']['key']) # add to student matched node set too to check while looping through the current level children (above) matchedStudentNodes.append( studentChild['child']['key']) elif len(teachChildNodesList) < len( studChildNodesList): matchedStudentNodes.append( studentChild['child']['key']) else: matchedStudentNodes.append( studentChild['child']['key']) break if matchFound == 'false' and not teacherChild['child'][ 'key'] in teachVisitedNodes: # len(teachChildNodesList) == len(studChildNodesList) and notMatchedParentTeacherNodes.append( teacherChild['child']['key']) elif matchFound == 'false' and teacherChild['child'][ 'key'] in teachVisitedNodes: feedback = feedback + 'The block:' + teacherChild['child']['text'] + \ ' should be connected to block:' + teacherCurrentText[0]['node.text'] + '. ' totNoOfOtherIncorrectNodes = totNoOfOtherIncorrectNodes + 1 if len(teachChildNodesList) == len(studChildNodesList) and len( notMatchedParentTeacherNodes) == 1: print('^^^ONE SUBSTITUTED NODE') totNoOfSubstitutedNodes, totNoOfOtherIncorrectNodes, feedback = \ addTheOnlyUnmatchedNode('NotMatchedNode', graph, notMatchedParentTeacherNodes, teachStack, studChildNodesList, matchedStudentNodes, studStack, totNoOfSubstitutedNodes, feedback, studVisitedNodes, teachCurrent, studentCurrentText[0]['node.text'], totNoOfOtherIncorrectNodes) elif len(teachChildNodesList) == len(studChildNodesList) and len( notMatchedParentTeacherNodes) > 1: totNoOfSubstitutedNodes = totNoOfSubstitutedNodes + len( notMatchedParentTeacherNodes) againNotMatchedTeacherNodes, handledStudentNodeList, feedback = checkForCurrentNodeChildMatch( 'substitutedCaller', graph, matchedStudentNodes, notMatchedParentTeacherNodes, studChildNodesList, studVisitedNodes, studStack, teachStack, feedback, studentCurrentText[0]['node.text']) if len(againNotMatchedTeacherNodes) == 1: totNoOfOtherIncorrectNodes, feedback = addTheOnlyUnmatchedNode( 'NotMatchedChildrenNode', graph, againNotMatchedTeacherNodes, teachStack, studChildNodesList, handledStudentNodeList, studStack, totNoOfSubstitutedNodes, feedback, studVisitedNodes, teachCurrent, studentCurrentText[0]['node.text'], totNoOfOtherIncorrectNodes) elif len(againNotMatchedTeacherNodes) > 1: for studentChild in studChildNodesList: if not studentChild['child'][ 'key'] in handledStudentNodeList and not studentChild[ 'child']['key'] in studVisitedNodes: feedback = feedback + 'The block:' + studentChild['child']['text'] + \ ' connected to block:' + studentCurrentText[0]['node.text'] + ' is substituted, and it ' for againNotTeacherNode in againNotMatchedTeacherNodes: teacherNodeText = graph.data( "MATCH (node:Teacher) WHERE node.key= {key} RETURN node.text", parameters={"key": againNotTeacherNode}) feedback = feedback + ' should be:' + teacherNodeText[ 0]['node.text'] + ' or' feedback = feedback + ' one of the mentioned blocks. The immediate blocks that follow ' +\ 'this block:' + studentChild['child']['text'] + ' are also wrong. Please check them. ' substitutedNodes.append( studentChild['child']['key']) # handles scenario where student graph has deleted child nodes for the current node under consideration if len(teachChildNodesList) > len(studChildNodesList): totNoOfDeletedNodes = totNoOfDeletedNodes + ( len(teachChildNodesList) - len(studChildNodesList)) if len(matchedStudentNodes) == len(studChildNodesList): for child in teachChildNodesList: if not child['child'][ 'key'] in matchedTeacherNodes and not child[ 'child']['key'] in teachVisitedNodes: feedback = feedback + 'Missing Block:' + child['child']['text'] + \ ' should be connected to block:' + studentCurrentText[0]['node.text'] + '. ' deletedNodes.append(child['child']['key']) elif len(matchedStudentNodes) < len(studChildNodesList): feedback = feedback + 'There is/are ' + str(len(teachChildNodesList) - len(studChildNodesList)) + \ ' missing block(s) that should be connected to block:' + studentCurrentText[0]['node.text'] + \ ' and ' + str(len(studChildNodesList) - len(matchedStudentNodes)) + \ ' block(s) connected to block:' + studentCurrentText[0]['node.text'] + \ ' is/are substituted - The incorrect blocks are ' againNotMatchedTeacherNodes, handledStudentNodeList, feedback = checkForCurrentNodeChildMatch( 'deletedSubstitutedCaller', graph, matchedStudentNodes, notMatchedParentTeacherNodes, studChildNodesList, studVisitedNodes, studStack, teachStack, feedback, studentCurrentText[0]['node.text']) if len(handledStudentNodeList) == len(studChildNodesList): for child in teachChildNodesList: if child['child'][ 'key'] in againNotMatchedTeacherNodes and not child[ 'child']['key'] in teachVisitedNodes: feedback = feedback + 'block:' + child['child']['text'] + \ ' that should be connected to block:' + studentCurrentText[0]['node.text'] +\ ' is missing and ' deletedNodes.append(child['child']['key']) elif len(handledStudentNodeList) < len(studChildNodesList): for child in teachChildNodesList: if child['child'][ 'key'] in againNotMatchedTeacherNodes and not child[ 'child']['key'] in teachVisitedNodes: feedback = feedback + ' block:' + child['child']['text'] + \ ' that should be/is connected to block:' + studentCurrentText[0]['node.text'] + \ ' is deleted/substituted and the immediate child blocks of this block are also wrong, please check them, and ' delOrSubNodes.append(child['child']['key']) feedback = feedback + 'please check all these incorrect blocks. ' # handles scenario where student graph has additional child nodes for the current node under consideration elif len(teachChildNodesList) < len(studChildNodesList): totNoOfAdditionalNodes = totNoOfAdditionalNodes + ( len(studChildNodesList) - len(teachChildNodesList)) # handles scenario where all teacher nodes are matched and there are additional nodes if len(matchedStudentNodes) == len(teachChildNodesList): for child in studChildNodesList: if not child['child'][ 'key'] in matchedStudentNodes and not child[ 'child']['key'] in studVisitedNodes: feedback = feedback + 'Additional Block:' + child['child']['text'] +\ ' is connected to block:' + studentCurrentText[0]['node.text'] + '. ' additionalNodes.append(child['child']['key']) elif not child['child'][ 'key'] in matchedStudentNodes and child[ 'child']['key'] in studVisitedNodes: feedback = feedback + 'Additional connection from block:' + studentCurrentText[0]['node.text'] +\ ' to block:' + child['child']['text'] + '. ' elif len(matchedStudentNodes) < len(teachChildNodesList): feedback = feedback + 'There is/are ' + str(len(studChildNodesList) - len(teachChildNodesList)) + \ ' additional block(s) connected to block:' + studentCurrentText[0]['node.text'] + ' and ' +\ str(len(teachChildNodesList) - len(matchedStudentNodes)) +\ ' block(s) connected to block:' + studentCurrentText[0]['node.text'] + ' is/are substituted - The incorrect blocks are ' againNotMatchedTeacherNodes, handledStudentNodeList, feedback = checkForCurrentNodeChildMatch( 'additionalSubstitutedCaller', graph, matchedStudentNodes, notMatchedParentTeacherNodes, studChildNodesList, studVisitedNodes, studStack, teachStack, feedback, studentCurrentText[0]['node.text']) if len(handledStudentNodeList) == len( teachChildNodesList ): # len(againNotMatchedTeacherNodes) == (len(studChildNodesList)-len(teachChildNodesList)) for child in studChildNodesList: if not child['child'][ 'key'] in handledStudentNodeList and not child[ 'child']['key'] in studVisitedNodes: feedback = feedback + 'block:' + child['child']['text'] + ' connected to block:' +\ studentCurrentText[0]['node.text'] + ' is additional and ' additionalNodes.append(child['child']['key']) elif len(handledStudentNodeList) < len( teachChildNodesList ): # len(againNotMatchedTeacherNodes) > (len(studChildNodesList)-len(teachChildNodesList)) for child in studChildNodesList: if not child['child'][ 'key'] in handledStudentNodeList and not child[ 'child']['key'] in studVisitedNodes: feedback = feedback + ' block: ' + child['child']['text'] + ' connected to block:' +\ studentCurrentText[0]['node.text'] +\ ' is additional/substituted and the immediate child blocks of this block are also wrong, please check them, and ' addOrSubNodes.append(child['child']['key']) feedback = feedback + 'please check all these incorrect blocks. ' matchedTeacherNodes = [] matchedStudentNodes = [] notMatchedParentTeacherNodes = [] teachVisitedNodes.append(teachCurrent) studVisitedNodes.append(studCurrent) elif studStack and not teachStack: print('^^^^^^^^^^^^^^^STUDENT stack has moreeee.....') break # handles additional nodes down an additional node starting path if additionalNodes: feedback, totNoOfAdditionalNodes = detectUndetectedBlocks( "additionalNodes", graph, additionalNodes, studVisitedNodes, feedback, totNoOfAdditionalNodes) # handles deleted nodes down a deleted node starting path if deletedNodes: feedback, totNoOfDeletedNodes = detectUndetectedBlocks( "deletedNodes", graph, deletedNodes, teachVisitedNodes, feedback, totNoOfDeletedNodes) # handles substituted nodes down a substituted node starting path if substitutedNodes: feedback, totNoOfOtherSubstitutedNodes = detectUndetectedBlocks( "substitutedNodes", graph, substitutedNodes, studVisitedNodes, feedback, totNoOfOtherSubstitutedNodes) # handles additional/substituted nodes down a additional/substituted node starting path if addOrSubNodes: feedback, totNoOfOtherIncorrectNodes = detectUndetectedBlocks( "addOrSubNodes", graph, addOrSubNodes, studVisitedNodes, feedback, totNoOfOtherIncorrectNodes) # handles deleted/substituted nodes down a deleted/substituted node starting path if delOrSubNodes: feedback, totNoOfOtherIncorrectNodes = detectUndetectedBlocks( "delOrSubNodes", graph, delOrSubNodes, teachVisitedNodes, feedback, totNoOfOtherIncorrectNodes) if totNoOfAdditionalNodes == 0 and totNoOfDeletedNodes == 0 and totNoOfSubstitutedNodes == 0 and \ totNoOfOtherSubstitutedNodes == 0 and totNoOfOtherIncorrectNodes == 0: print(totNoOfMatchedNodes) feedback = feedback + "Excellent Job! All the blocks and the flow are correct!" # Number of correct blocks: " + ". " print(feedback) else: feedback = feedback + "Number of correct blocks except start and end blocks: " + str( totNoOfMatchedNodes) + ". " print(feedback) allocateMarksAndSaveToDatabase(totNoOfMatchedNodes, totNoOfAdditionalNodes, totNoOfDeletedNodes, totNoOfSubstitutedNodes, totNoOfOtherSubstitutedNodes, totNoOfOtherIncorrectNodes, feedback, processQuestionId, studentAnswerId)
def runDFSAndAddStatementToPyFile(studentAnswerFile): # Connect to Graph graph = connectToGraph() studentStartNodeKey = graph.data( "MATCH (node:Student) WHERE node.symbol='Start' RETURN node.key") stack = [studentStartNodeKey[0]['node.key']] visitedNodes = [] outputVariableNames = [] currentStructure = "" # maintains common nodes in paths for all if structures commonNodes = [] # maintain all nodes traversed and visited including ones not completed analyzing traversedNodes = [] # this dictionary has keys which are the node keys of ifs under analysis until main if path is joined and values are # an indication of the number of times the path joining node must be visited to continue and further reduce the # indentation. Yes path will have it corresponding values because yes is analyzed first while no path will have the # summation of yes completed ones and the corresponding no path ifs, yes has already been traversed, and that many # has to be traversed by the time of no path unindentations. ifDictionary = {} # maintains if node keys for if-else structures ifNodes = [] doWhileNodes = [] whileNodes = [] mainIfCompletedNoOfPaths = 0 indent = 0 while stack: currentNode = stack.pop() traversedNodes.append(currentNode) continueWithFlow = 'false' if not commonNodes: continueWithFlow = 'true' while commonNodes: currentCommonNode = commonNodes.pop() if currentNode == currentCommonNode: indent = indent - 1 currentIfKey = ifNodes.pop() if traversedNodes.count(currentNode) < ifDictionary.get( currentIfKey, "none"): commonNodes.append(currentCommonNode) ifNodes.append(currentIfKey) break elif traversedNodes.count(currentNode) == ifDictionary.get( currentIfKey, "none"): continueWithFlow = 'true' if not currentNode in commonNodes: traversedNodes[:] = (key for key in traversedNodes if key != currentNode) traversedNodes.append(currentNode) continue else: continueWithFlow = 'true' commonNodes.append(currentCommonNode) break if not commonNodes: ifDictionary = {} ifNodes = [] mainIfCompletedNoOfPaths = 0 if continueWithFlow == "true": currentNodeInfo = graph.data( "MATCH (node:Student) WHERE node.key= {key} RETURN node", parameters={"key": currentNode}) currentSymbol = currentNodeInfo[0]['node']['symbol'] currentText = currentNodeInfo[0]['node']['text'] currentNodeParents = graph.data( "MATCH (parent:Student)-[]->(child:Student) WHERE child.key= {key} RETURN parent", parameters={"key": currentNode}) if indent > 0: if doWhileNodes and not whileNodes: if not doWhileNodes[-1] == currentNode: indentLine(indent, studentAnswerFile) elif whileNodes and not doWhileNodes: if not whileNodes[-1] == currentNode: indentLine(indent, studentAnswerFile) elif doWhileNodes and whileNodes: if not (doWhileNodes[-1] == currentNode or whileNodes[-1] == currentNode): indentLine(indent, studentAnswerFile) else: indentLine(indent, studentAnswerFile) if currentSymbol == "Input": if '\'' in currentText: words = re.split("[,]+", currentText) else: words = re.split("[, ]+", currentText) for word in words: if not (re.match("input", word, re.IGNORECASE) or re.match("enter", word, re.IGNORECASE) or re.match("read", word, re.IGNORECASE) or '\'' in word or not word): variable = word.strip() #.replace(",", "") studentAnswerFile.write( variable + " = float(str(sys.argv[argCount]))\n") if indent > 0: indentLine(indent, studentAnswerFile) studentAnswerFile.write("argCount = argCount + 1\n") elif currentSymbol == "Process": studentAnswerFile.write(currentText + "\n") elif currentSymbol == "Output": if '+' in currentText and '\'' in currentText: words = re.split("[+,]+", currentText) elif ',' in currentText and '\'' in currentText and not '+' in currentText: words = re.split("[,]+", currentText) elif '\'' in currentText and not (',' in currentText or '+' in currentText): words = re.split("[']+", currentText) else: words = re.split("[, ]+", currentText) print(words) for wordSet in words: if not (re.search("output", wordSet, re.IGNORECASE) or re.search("display", wordSet, re.IGNORECASE) or re.search("print", wordSet, re.IGNORECASE) or '\'' in wordSet or not wordSet): variable = wordSet.strip() # + or , means there is a variable if ',' in currentText or '+' in currentText: # output has numeric variables outputVariableNames.append(variable) studentAnswerFile.write("print(" + "str(" + variable + ")" + ")\n") elif not (',' in currentText or '+' in currentText) and '\'' in currentText: # output is just one string value studentAnswerFile.write("print('" + variable + "')\n") else: # output has numeric variable outputVariableNames.append(variable) studentAnswerFile.write("print(" + "str(" + variable + ")" + ")\n") elif currentSymbol == "Decision": yesCurrentChildNode = graph.data( "MATCH (parent:Student)-[:YES]->(child:Student) WHERE parent.key= {key} RETURN child", parameters={"key": currentNode}) yesChildParents = graph.data( "MATCH (parent:Student)-[]->(child:Student) WHERE child.key= {key} RETURN parent", parameters={"key": yesCurrentChildNode[0]['child']['key']}) noCurrentChildNode = graph.data( "MATCH (parent:Student)-[:NO]->(child:Student) WHERE parent.key= {key} RETURN child", parameters={"key": currentNode}) noChildParents = graph.data( "MATCH (parent:Student)-[]->(child:Student) WHERE child.key= {key} RETURN parent", parameters={"key": noCurrentChildNode[0]['child']['key']}) doWhileFound = "false" unindentWhile = "false" if ((yesCurrentChildNode[0]['child']['key'] in visitedNodes or noCurrentChildNode[0]['child']['key'] in visitedNodes) \ and traversedNodes.count(currentNode) == 1) or currentNode in doWhileNodes: doWhileFound = "true" if yesCurrentChildNode[0]['child']['key'] in visitedNodes: whileOrNot = "while " if traversedNodes.count(currentNode) == 1: whileNextNode = yesCurrentChildNode[0]['child'][ 'key'] elif traversedNodes.count(currentNode) > 1: whileNextNode = noCurrentChildNode[0]['child'][ 'key'] elif noCurrentChildNode[0]['child']['key'] in visitedNodes: whileOrNot = "while not " if traversedNodes.count(currentNode) == 1: whileNextNode = noCurrentChildNode[0]['child'][ 'key'] elif traversedNodes.count(currentNode) > 1: whileNextNode = yesCurrentChildNode[0]['child'][ 'key'] currentStructure = "DoWhile" line, indent, unindentWhile, traversedNodes = handleWhileTypeConversions( currentStructure, stack, whileNextNode, traversedNodes, currentNode, indent, unindentWhile, whileOrNot, currentText, doWhileNodes, visitedNodes) else: if (len(whileNodes) == 0 and traversedNodes.count(currentNode) == 1) or \ (len(whileNodes) == 1 and traversedNodes.count(currentNode) == 2): loopPath = graph.data( "MATCH (currentNode:Student)-[r:YES|NO]->(nextNode:Student)-[*]->" + "(currentNode:Student) WHERE currentNode.key = {currentNodeKey} RETURN DISTINCT TYPE(r)", parameters={"currentNodeKey": currentNode}) elif (len(whileNodes) == 1 and traversedNodes.count(currentNode) == 1) or \ (len(whileNodes) == 2 and traversedNodes.count(currentNode) == 2): loopPath = graph.data( "MATCH path = (currentNode:Student)-[r:YES|NO]->(nextNode:Student)-[*]->" "(currentNode:Student) WHERE currentNode.key = {currentNodeKey} " "WITH path, r MATCH (previousIfNode: Student) WHERE previousIfNode.key = " "{previousIfNodeKey} AND NOT previousIfNode IN NODES(path) RETURN TYPE(r)", parameters={ "currentNodeKey": currentNode, "previousIfNodeKey": whileNodes[0] }) elif (len(whileNodes) == 2 and traversedNodes.count(currentNode) == 1) or \ (len(whileNodes) == 3 and traversedNodes.count(currentNode) == 2): loopPath = graph.data( "MATCH path = (currentNode:Student)-[r:YES|NO]->(nextNode:Student)-[*]->" "(currentNode:Student) WHERE currentNode.key = {currentNodeKey} " "WITH path, r MATCH (previousIfNodeOne: Student), " "(previousIfNodeTwo: Student) WHERE (previousIfNodeOne.key = " "{previousIfNodeOneKey} AND NOT previousIfNodeOne IN NODES(path)) AND " "(previousIfNodeTwo.key = {previousIfNodeTwoKey} AND NOT previousIfNodeTwo " "IN NODES(path)) RETURN TYPE(r)", parameters={ "currentNodeKey": currentNode, "previousIfNodeOneKey": whileNodes[0], "previousIfNodeTwoKey": whileNodes[1] }) if not loopPath: line, currentStructure, mainIfCompletedNoOfPaths = handleIfTypeConversions( graph, stack, currentNode, traversedNodes, noChildParents, yesChildParents, noCurrentChildNode, yesCurrentChildNode, currentText, commonNodes, ifNodes, ifDictionary, visitedNodes, mainIfCompletedNoOfPaths) else: if commonNodes or whileNodes or doWhileNodes: if (len(whileNodes) == 0 and traversedNodes.count(currentNode) == 1) or \ (len(whileNodes) == 1 and traversedNodes.count(currentNode) == 2) or \ (len(whileNodes) == 0 and traversedNodes.count(currentNode) == 2): loopPathLength = graph.data( "MATCH path = (currentNode:Student)-[r:YES|NO]->(nextNode:Student)-[*]->" + "(currentNode:Student) WHERE currentNode.key = " + "{currentNodeKey} RETURN length(path)", parameters={"currentNodeKey": currentNode}) elif (len(whileNodes) == 1 and traversedNodes.count(currentNode) == 1) or \ (len(whileNodes) == 2 and traversedNodes.count(currentNode) == 2): loopPathLength = graph.data( "MATCH path = (currentNode:Student)-[r:YES|NO]->(nextNode:Student)-[*]->" + "(currentNode:Student) WHERE currentNode.key = {currentNodeKey} WITH path, r " + "MATCH (previousIfNode:Student) WHERE previousIfNode.key = {previousIfNodeKey} " + "AND NOT previousIfNode IN NODES(path) RETURN length(path)", parameters={ "currentNodeKey": currentNode, "previousIfNodeKey": whileNodes[0] }) elif (len(whileNodes) == 2 and traversedNodes.count(currentNode) == 1) or \ (len(whileNodes) == 3 and traversedNodes.count(currentNode) == 2): loopPathLength = graph.data( "MATCH path = (currentNode:Student)-[r:YES|NO]->(nextNode:Student)-[*]->" + "(currentNode:Student) WHERE currentNode.key = {currentNodeKey} WITH path, r " + "MATCH (previousIfNodeOne:Student), " "(previousIfNodeTwo:Student) WHERE (previousIfNodeOne.key = " "{previousIfNodeOneKey} AND NOT previousIfNodeOne IN NODES(path)) AND " "(previousIfNodeTwo.key = {previousIfNodeTwoKey} AND NOT previousIfNodeTwo " "IN NODES(path)) RETURN length(path)", parameters={ "currentNodeKey": currentNode, "previousIfNodeOneKey": whileNodes[0], "previousIfNodeTwoKey": whileNodes[1] }) curCommonNodePathLength = graph.data( "MATCH path1 = (currentDecision:Student)-[:YES]->(a:Student)-[*]->(commonNode:Student), " + "path2 = (currentDecision:Student)-[:NO]->(b:Student)-[*]->" + "(commonNode:Student) WHERE currentDecision.key={currentNodeKey} and path1 <> path2 " + "and currentDecision <> commonNode RETURN length(path2)", parameters={"currentNodeKey": currentNode}) if not curCommonNodePathLength: curCommonNodePathLength = graph.data( "MATCH path1 = (currentDecision:Student)-[:YES]->(a:Student)-[*]->" + "(commonNode:Student), path2 = (currentDecision:Student)-[:NO]->" + "(commonNode:Student) WHERE currentDecision.key={currentNodeKey} and " + "path1 <> path2 and currentDecision <> commonNode RETURN length(path2)", parameters={"currentNodeKey": currentNode}) if not curCommonNodePathLength: curCommonNodePathLength = graph.data( "MATCH path1 = (currentDecision:Student)-[:YES]->(commonNode:Student), " + "path2 = (currentDecision:Student)-[:NO]->(b:Student)-[*]->(commonNode:Student) " + "WHERE currentDecision.key={currentNodeKey} and path1 <> path2 and " + "currentDecision <> commonNode RETURN length(path1)", parameters={"currentNodeKey": currentNode}) if not curCommonNodePathLength: whileOrNot, whileNextNode, currentStructure = handleWhileTraversal( loopPath, traversedNodes, currentNode, yesCurrentChildNode, noCurrentChildNode) line, indent, unindentWhile, traversedNodes = handleWhileTypeConversions( currentStructure, stack, whileNextNode, traversedNodes, currentNode, indent, unindentWhile, whileOrNot, currentText, whileNodes, visitedNodes) elif not loopPathLength: line, currentStructure, mainIfCompletedNoOfPaths = handleIfTypeConversions( graph, stack, currentNode, traversedNodes, noChildParents, yesChildParents, noCurrentChildNode, yesCurrentChildNode, currentText, commonNodes, ifNodes, ifDictionary, visitedNodes, mainIfCompletedNoOfPaths) else: if loopPathLength[0][ 'length(path)'] > curCommonNodePathLength[ 0]['length(path2)']: line, currentStructure, mainIfCompletedNoOfPaths = handleIfTypeConversions( graph, stack, currentNode, traversedNodes, noChildParents, yesChildParents, noCurrentChildNode, yesCurrentChildNode, currentText, commonNodes, ifNodes, ifDictionary, visitedNodes, mainIfCompletedNoOfPaths) else: whileOrNot, whileNextNode, currentStructure = handleWhileTraversal( loopPath, traversedNodes, currentNode, yesCurrentChildNode, noCurrentChildNode) line, indent, unindentWhile, traversedNodes = handleWhileTypeConversions( currentStructure, stack, whileNextNode, traversedNodes, currentNode, indent, unindentWhile, whileOrNot, currentText, whileNodes, visitedNodes) else: whileOrNot, whileNextNode, currentStructure = handleWhileTraversal( loopPath, traversedNodes, currentNode, yesCurrentChildNode, noCurrentChildNode) line, indent, unindentWhile, traversedNodes = handleWhileTypeConversions( currentStructure, stack, whileNextNode, traversedNodes, currentNode, indent, unindentWhile, whileOrNot, currentText, whileNodes, visitedNodes) if unindentWhile == "false": studentAnswerFile.write(line + "\n") indent = indent + 1 if not (currentSymbol == "Decision" or currentSymbol == 'End'): currentChildNodes = graph.data( "MATCH (parent:Student)-[:TO]->(child:Student) WHERE parent.key= {key} RETURN child", parameters={"key": currentNode}) stack.append(currentChildNodes[0]['child']['key']) visitedNodes.append(currentNode) return outputVariableNames