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

Commit e98ebad

Browse files
committed
Add jsnx library to help calculate mvc
1 parent fc170d3 commit e98ebad

5 files changed

Lines changed: 197 additions & 6 deletions

File tree

package-lock.json

Lines changed: 84 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
"author": "",
1919
"license": "ISC",
2020
"devDependencies": {
21-
"copy-webpack-plugin": "^9.0.0",
2221
"compression-webpack-plugin": "^9.0.0",
22+
"copy-webpack-plugin": "^9.0.0",
2323
"css-loader": "^6.0.0",
2424
"css-minimizer-webpack-plugin": "^3.0.0",
2525
"html-loader": "^3.0.0",
@@ -36,6 +36,7 @@
3636
"handsontable": "7.2.2",
3737
"jexcel": "^3.9.1",
3838
"jquery-ui": "1.10.4",
39+
"jsnetworkx": "^0.3.4",
3940
"select2": "^4.1.0-rc.0",
4041
"sql.js": "1.5.0",
4142
"vega-embed": "3.14.0",

runestone/parsons/js/dagGrader.js

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,102 @@
11
import LineBasedGrader from "./lineGrader";
2+
import { DiGraph } from "jsnetworkx/node/classes";
3+
import { hasPath } from "jsnetworkx/node/algorithms/shortestPaths/generic";
4+
5+
function graphToNX(answerBlocks) {
6+
var graph = new DiGraph();
7+
for (let block of answerBlocks) {
8+
let line = block.lines[0]; // FIXME assume each block only has one line, won't work with adaptivity
9+
graph.addNode(line.tag);
10+
for (let line2 of line.depends) {
11+
// the depends graph lists the *incoming* edges of a node
12+
graph.addEdge(line2, line);
13+
}
14+
}
15+
return graph;
16+
}
17+
18+
function isVertexCover(graph, vertexCover) {
19+
for (let edge of graph.edges()) {
20+
if (!(vertexCover.has(edge[0]) || vertexCover.has(edge[1]))) {
21+
return false;
22+
}
23+
}
24+
return true;
25+
}
26+
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+
}
247

348
export default class DAGGrader extends LineBasedGrader {
449

5-
inverseLISIndices(arr) {
6-
// TODO implement this properly for the DAG grader so that it is the shortest edit distance
50+
51+
inverseLISIndices(answerBlocks, solution) {
52+
// For more details and a proof of the correctness of the algorithm, see the paper: https://arxiv.org/abs/2204.04196
53+
let graph = graphToNX(answerBlocks);
54+
console.log(allSubsets([1,2,3]))
55+
56+
let seen = new Set();
57+
let problematicSubgraph = new DiGraph();
58+
let distractors = [];
59+
for (let block of solution) {
60+
61+
if (block.distractor) {
62+
distractors.push(block);
63+
continue;
64+
}
65+
66+
for (let block2 of seen) {
67+
let problematic = hasPath(graph, block, block2);
68+
if (hasPath(graph, block, block2)) {
69+
problematicSubgraph.addEdge(block, block2);
70+
}
71+
}
72+
73+
seen.add(block);
74+
}
75+
76+
console.log(problematicSubgraph);
77+
78+
if (problematicSubgraph.numberOfNodes() == 0) {
79+
// just return the indices of the distractors, I guess???
80+
} else {
81+
let mvc = null;
82+
let subsets = allSubsets(problematicSubgraph.nodes());
83+
for (let i = 0; i <= problematicSubgraph.numberOfNodes(); i++) {
84+
for (let subset of subsets[i]) {
85+
if (isVertexCover(problematicSubgraph, subset)) {
86+
mvc = subset;
87+
console.log(mvc)
88+
break;
89+
}
90+
}
91+
if (mvc != null) {
92+
break;
93+
}
94+
}
95+
}
96+
97+
// TODO implement the algorithm properly for the DAG grader so that it is the shortest edit distance
798
// to ANY of the correct solutions instead of just to the model solution
8-
return super.inverseLISIndices(arr)
99+
return super.inverseLISIndices(answerBlocks, solution)
9100
}
10101

11102
checkCorrectOrdering(solutionLines, answerLines) {

runestone/parsons/js/lineGrader.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,22 @@ export default class LineBasedGrader {
44
}
55
// Use a LIS (Longest Increasing Subsequence) algorithm to return the indexes
66
// that are not part of that subsequence.
7-
inverseLISIndices(arr) {
7+
inverseLISIndices(answerBlocks, solution) {
8+
var inSolution = [];
9+
var inSolutionIndexes = [];
10+
var notInSolution = [];
11+
for (let i = 0; i < answerBlocks.length; i++) {
12+
var block = answerBlocks[i];
13+
var index = solution.indexOf(block.lines[0]);
14+
if (index == -1) {
15+
notInSolution.push(block);
16+
} else {
17+
inSolution.push(block);
18+
inSolutionIndexes.push(index);
19+
}
20+
}
21+
let arr = inSolutionIndexes;
22+
823
// Get all subsequences
924
var allSubsequences = [];
1025
for (var i = 0; i < arr.length; i++) {

runestone/parsons/js/parsons.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1424,7 +1424,7 @@ export default class Parsons extends RunestoneBase {
14241424
inSolutionIndexes.push(index);
14251425
}
14261426
}
1427-
var lisIndexes = this.grader.inverseLISIndices(inSolutionIndexes);
1427+
var lisIndexes = this.grader.inverseLISIndices(this.answerBlocks(), this.solution);
14281428
for (let i = 0; i < lisIndexes.length; i++) {
14291429
notInSolution.push(inSolution[lisIndexes[i]]);
14301430
}

0 commit comments

Comments
 (0)