def binaryTree(student_answer, downwards): if downwards == "top": down = True elif downwards == "bottom": down = False else: raise Exception('Unknown parameter value supplied. Contact support.') root = 0 for v in student_answer.vs: split = splitParentChildren(v, down) if split == None: return {'correct': False, 'feedback': 'same height of nodes'} (par, chil) = split if len(par) > 1: return { 'correct': False, 'feedback': 'too many parents', 'vertexLabel': filter_orig_name(v) } elif len(par) == 0: root += 1 if len(chil) > 2: return { 'correct': False, 'feedback': 'too many children', 'vertexLabel': filter_orig_name(v) } if root > 1: return {'correct': False, 'feedback': 'too many roots'} return {'correct': True}
def inLeaf(student_answer, labels, downwards): if downwards == "top": down = True elif downwards == "bottom": down = False else: raise Exception('Unknown parameter value supplied. Contact support.') for v in student_answer.vs: v_orig = filter_orig_name(v) if v_orig in labels: split = splitParentChildren(v, down) if split == None: return None (par, chil) = split if len(chil) != 0: return { 'correct': False, 'feedback': 'not in leaf', 'element': v_orig } labels.remove(v_orig) if (len(labels) != 0): return { 'correct': False, 'feedback': "missing element", 'exampleElement': labels[0] } else: return {'correct': True}
def heap_layout(student_answer): #find the root #throw error if there is more than one root, or if a node has multiple parents root = findRoot(student_answer, True) #check if a problem was encountered if (root == None): return {'correct': False, 'feedback': 'layout problem'} layer = [root] nextLayer = [] noMoreChildren = False while len(layer) > 0: for v in layer: value = splitParentChildren(v, True) if (value == None): return {'correct': False, 'feedback': 'There is a problem with the layout that makes distinguishing the heap impossible.'} (par, chil) = value if noMoreChildren and len(chil) > 0: return {'correct': False, 'feedback': 'level incorrect'} if (len(chil) > 2): return {'correct': False, 'feedback': 'too many children', 'vertexLabel': filter_orig_name(v), } elif len(chil) == 1: if chil[0]['x'] > v['x']: return {'correct': False, 'feedback': 'missing left child', 'vertexLabel': filter_orig_name(v) } noMoreChildren = True elif len(chil) == 0: noMoreChildren = True else: left_child = chil[0] right_child = chil[1] if left_child["x"] > right_child["x"]: left_child = chil[1] right_child = chil[0] nextLayer.append(left_child) nextLayer.append(right_child) layer = nextLayer nextLayer = [] return {'correct': True}
def check_heap_structure(student_answer, comparator, textual): #for each node, check that the children are smaller or equally large as the parent for v in student_answer.vs: split = splitParentChildren(v, True) if (split == None): return {'correct': False, 'feedback': 'layout problem'} (par, chil) = split valueV = int(filter_orig_name(v)) for w in chil: valueW = int(filter_orig_name(w)) if comparator(valueV, valueW): return {'correct': False, 'feedback': 'child parent wrong', 'vertexLabel1': filter_orig_name(v), 'greater_smaller': textual, 'vertexLabel2': filter_orig_name(w)} return {'correct': True}
def traverse(node, labels, downwards): exc = None (left, right) = children(node, downwards) if (not left == None): (labels, exc) = traverse(left, labels, downwards) if (len(labels) == 0): return (labels, {'correct': False, "feedback": "too many nodes"}) if (filter_orig_name(node) == str(labels[0])): labels.pop(0) else: return (labels, { 'correct': False, "feedback": "mismatched labels", "vertexLabel": filter_orig_name(node), "expectedLabel": labels[0] }) if (not right == None): (labels, exc) = traverse(right, labels, downwards) return (labels, exc)
def same_highlights(student_answer, expected): if not student_answer.isomorphic(expected): return {'correct': False, 'feedback': 'not isomorphic graphs'} #inefficient for v in student_answer.vs: vName = filter_orig_name(v) for w in expected.vs: wName = filter_orig_name(w) if vName == wName: if v['highlighted'] != w['highlighted']: return { 'correct': False, 'feedback': 'highlighted vertices mismatched' } break for e in student_answer.es: eSource = filter_orig_name(student_answer.vs[e.source]) eTarget = filter_orig_name(student_answer.vs[e.target]) for f in expected.es: fSource = filter_orig_name(expected.vs[f.source]) fTarget = filter_orig_name(expected.vs[f.target]) if (eSource == fSource and eTarget == fTarget) or (eSource == fTarget and eTarget == fSource): if e['highlighted'] != f['highlighted']: return { 'correct': False, 'feedback': 'highlighted edges mismatched' } break return {'correct': True}
def coloring(student_answer, noColors): colors = set() for v in student_answer.vs: colors.add(v['color']) for w in student_answer.neighbors(v): wVert = student_answer.vs[w] if wVert['color'] == v['color']: return { 'correct': False, 'feedback': 'Vertices \'{0}\' en \'{1}\' are adjacent and have the same color.' .format(filter_orig_name(v), filter_orig_name(wVert)) } if len(colors) > noColors: return { 'correct': False, 'feedback': 'color count wrong', 'colorCount': len(colors), 'expectedColorCount': noColors } return {'correct': True}
def binarySearchTree(student_answer, downwards): bTree = binaryTree(student_answer, downwards) if not bTree['correct']: return bTree labels = [] for v in student_answer.vs: try: label = filter_orig_name(v) labels.append(int(label)) except: return { 'correct': False, 'feedback': 'label not numerical', 'vertexLabel': filter_orig_name(v) } labels.sort() iOrder = inOrderTraversal(student_answer, labels, downwards) if not iOrder['correct']: return {'correct': False, 'feedback': 'not sorted order'} else: return {'correct': True}
def vertex_degree_at_most(student_answer, max_degree): for v in student_answer.vs: if v.degree() > max_degree: v_name = filter_orig_name(v) if not v_name: v_name = '-no label-' return { 'correct': False, 'feedback': 'max degree too high', 'vertexLabel': v_name, 'vertexDegree': v.degree(), 'maxDegree': max_degree } return {'correct': True}
def nodeDepth(student_answer, label, depth, downwards): if downwards == "top": down = True elif downwards == "bottom": down = False else: raise Exception('Unknown parameter value supplied. Contact support.') for v in student_answer.vs: if filter_orig_name(v) == label: vertex = v dep = 0 while not v == None: split = splitParentChildren(v, down) if split == None: return {'correct': False, 'feedback': 'layout problem'} (par, chil) = split if len(par) > 1: return {'correct': False, 'feedback': 'layout problem'} elif len(par) == 1: dep += 1 v = par[0] elif dep == depth: return {'correct': True} else: return { 'correct': False, 'feedback': 'depth wrong', 'vertexLabel': label, 'depthReal': dep, 'depthExpected': depth } return { 'correct': False, 'feedback': 'missing vertex', 'vertexLabel': label }
def equivalent(student_answer, graph_answer, colors_choice, edge_choice): check_colors = colors_choice == "yes" check_edge_labels = edge_choice == "yes" if len(student_answer.vs) != len(graph_answer.vs): return { 'correct': False, 'feedback': 'vertex count wrong', 'vertexCount': len(student_answer.vs), 'expectedVertexCount': len(graph_answer.vs) } if len(student_answer.es) != len(graph_answer.es): return { 'correct': False, 'feedback': 'edge count wrong', 'edgeCount': len(student_answer.es), 'expectedEdgeCount': len(graph_answer.es) } vs_stud = sorted(student_answer.vs, key=lambda vertex: vertex['name']) vs_graph = sorted(graph_answer.vs, key=lambda vertex: vertex['name']) for i in range(0, len(vs_graph)): #check if the matching vertex exists if (vs_stud[i]['name'] != vs_graph[i]['name']): return { 'correct': False, 'feedback': 'missing vertex', 'vertexLabel': filter_orig_name(vs_graph[i]) } if (vs_stud[i].degree() != vs_graph[i].degree()): return { 'correct': False, 'feedback': 'degree wrong', 'vertexLabel': filter_orig_name(vs_graph[i]), 'vertexDegree': vs_stud[i].degree(), 'expectedDegree': vs_graph[i].degree() } if (check_colors and vs_stud[i]['color'] != vs_graph[i]['color']): return { 'correct': False, 'feedback': 'color wrong', 'vertexLabel': filter_orig_name(vs_graph[i]), 'vertexColor': vs_stud[i]['color'], 'expectedColor': vs_graph[i]['color'] } graph_neigh = sorted(vs_graph[i].neighbors(), key=lambda vertex: vertex['name']) stud_neigh = sorted(vs_stud[i].neighbors(), key=lambda vertex: vertex['name']) for j in range(0, len(graph_neigh)): if (graph_neigh[j]['name'] != stud_neigh[j]['name']): return { 'correct': False, 'feedback': 'neighborhood wrong', 'vertexLabel': filter_orig_name(vs_graph[i]) } if (check_edge_labels): graph_edges = sorted(vs_graph[i].all_edges(), key=lambda edge: edge['label']) stud_edges = sorted(vs_stud[i].all_edges(), key=lambda edge: edge['label']) for j in range(0, len(graph_edges)): if (graph_edges[j]['label'] != stud_edges[j]['label']): return { 'correct': False, 'feedback': 'edge label wrong', 'edgeLabel': str(stud_edges[j]['label']), 'fromLabel': filter_orig_name( student_answer.vs[stud_edges[j].source]), 'toLabel': filter_orig_name( student_answer.vs[stud_edges[j].target]) } return {'correct': True}