Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit bb8d519

Browse files
committed
Merge branch 'SethPoulsen-proof-blocks'
2 parents fef3cee + 16ec1bc commit bb8d519

File tree

7 files changed

+671
-20
lines changed

7 files changed

+671
-20
lines changed

runestone/parsons/js/dagGrader.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import LineBasedGrader from "./lineGrader";
2+
import { DiGraph, hasPath, isDirectedAcyclicGraph } from "./dagHelpers";
3+
4+
function graphToNX(answerLines) {
5+
var graph = new DiGraph();
6+
for (let line1 of answerLines) {
7+
graph.addNode(line1.tag);
8+
for (let line2tag of line1.depends) {
9+
// the depends graph lists the *incoming* edges of a node
10+
graph.addEdge(line2tag, line1.tag);
11+
}
12+
}
13+
return graph;
14+
}
15+
16+
function isVertexCover(graph, vertexCover) {
17+
for (let edge of graph.edges()) {
18+
if (!(vertexCover.has(edge[0]) || vertexCover.has(edge[1]))) {
19+
return false;
20+
}
21+
}
22+
return true;
23+
}
24+
25+
// Find all subsets of the set using the correspondence of subsets of
26+
// a set to binary string whose length are the size of the set
27+
function allSubsets(arr) {
28+
let subsets = {};
29+
for (let i = 0; i <= arr.length; i++) {
30+
subsets[i] = [];
31+
}
32+
for (let i = 0; i < Math.pow(2, arr.length); i++) {
33+
let bin = i.toString(2);
34+
while (bin.length < arr.length) {
35+
bin = "0" + bin;
36+
}
37+
let subset = new Set();
38+
for (let j = 0; j < bin.length; j++) {
39+
if (bin[j] == "1") {
40+
subset.add(arr[j]);
41+
}
42+
}
43+
subsets[subset.size].push(subset);
44+
}
45+
return subsets;
46+
}
47+
48+
export default class DAGGrader extends LineBasedGrader {
49+
inverseLISIndices(arr, inSolution) {
50+
// For more details and a proof of the correctness of the algorithm, see the paper: https://arxiv.org/abs/2204.04196
51+
52+
var solution = this.problem.solution;
53+
var answerLines = inSolution.map((block) => block.lines[0]); // assume NOT adaptive for DAG grading (for now)
54+
55+
let graph = graphToNX(solution);
56+
57+
let seen = new Set();
58+
let problematicSubgraph = new DiGraph();
59+
for (let line1 of answerLines) {
60+
for (let line2 of seen) {
61+
let problematic = hasPath(graph, {
62+
source: line1.tag,
63+
target: line2.tag,
64+
});
65+
if (problematic) {
66+
problematicSubgraph.addEdge(line1.tag, line2.tag);
67+
}
68+
}
69+
70+
seen.add(line1);
71+
}
72+
73+
let mvc = null;
74+
let subsets = allSubsets(problematicSubgraph.nodes());
75+
for (let i = 0; i <= problematicSubgraph.numberOfNodes(); i++) {
76+
for (let subset of subsets[i]) {
77+
if (isVertexCover(problematicSubgraph, subset)) {
78+
mvc = subset;
79+
break;
80+
}
81+
}
82+
if (mvc != null) {
83+
break;
84+
}
85+
}
86+
87+
let indices = [...mvc].map((tag) => {
88+
for (let i = 0; i < answerLines.length; i++) {
89+
if (answerLines[i].tag === tag) return i;
90+
}
91+
});
92+
return indices;
93+
}
94+
95+
checkCorrectOrdering(solutionLines, answerLines) {
96+
if (!isDirectedAcyclicGraph(graphToNX(solutionLines))) {
97+
throw "Dependency between blocks does not form a Directed Acyclic Graph; Problem unsolvable.";
98+
}
99+
100+
let seen = new Set();
101+
let isCorrectOrder = true;
102+
this.correctLines = 0;
103+
this.solutionLength = solutionLines.length;
104+
let loopLimit = Math.min(solutionLines.length, answerLines.length);
105+
for (let i = 0; i < loopLimit; i++) {
106+
let line = answerLines[i];
107+
if (line.distractor) {
108+
isCorrectOrder = false;
109+
} else {
110+
for (let j = 0; j < line.depends.length; j++) {
111+
if (!seen.has(line.depends[j])) {
112+
isCorrectOrder = false;
113+
}
114+
}
115+
}
116+
if (isCorrectOrder) {
117+
this.correctLines += 1;
118+
}
119+
seen.add(line.tag);
120+
}
121+
return isCorrectOrder;
122+
}
123+
}

0 commit comments

Comments
 (0)