Skip to content

Commit

Permalink
make things a little more proper
Browse files Browse the repository at this point in the history
  • Loading branch information
alltom committed Dec 29, 2013
1 parent 72c2f97 commit 85f4382
Show file tree
Hide file tree
Showing 6 changed files with 639 additions and 305 deletions.
File renamed without changes.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Propagators
===========
201 changes: 201 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
var _ = require("underscore");

function Scheduler() {
var self = {};
var propagatorsEverAlerted = [];
var alertedPropagators = [];

self.alertPropagators = function (propagators) {
propagatorsEverAlerted = _.union(propagatorsEverAlerted, propagators);
alertedPropagators = _.union(alertedPropagators, propagators);
};

self.alertPropagator = function (propagator) {
self.alertPropagators([propagator]);
};

self.alertAllPropagators = function () {
alertPropagators(propagatorsEverAlerted);
};

self.addPropagator = function (neighbors, toDo) {
_.each(neighbors, function (cell) {
cell.addNeighbor(toDo);
});
self.alertPropagator(toDo);
}

self.run = function () {
var ticks = 0;
while (alertedPropagators.length > 0) {
ticks++;
alertedPropagators.pop()();
}
return ticks;
};


// (d@ propagator boundary-cell ...)
// propagator is a cell containing a propagator constructor for attaching propagators
self.diagramApply = function (propagator, boundaryCells) {
if (propagator.content()) {
propagator.content()(self, boundaryCells);
} else {
self.addPropagator([propagator], function () {
if (propagator.content()) {
propagator.content()(self, boundaryCells);
}
});
}
};

// (e@ propagator boundary-cell ...)
// like d@, but synthesizes an output cell and returns it
self.expressionApply = function (propagator, boundaryCells) {
var output = self.Cell();
self.diagramApply(propagator, boundaryCells.concat(output));
return output;
};

makeCellConstructor();
makeDefaultPropagators();

return self;

// content is optional
function makeCellConstructor() {
var scheduler = self;
self.Cell = Cell;

function Cell(content) {
var self = {};
var neighbors = [];
var content = content;

self.content = function () {
return content;
};

self.addContent = function (increment) {
var answer = merge(content, increment);

if (!equivalent(content, answer)) {
content = answer;
scheduler.alertPropagators(neighbors);
}
};

self.addNeighbor = function (neighbor) {
neighbors = _.union(neighbors, [neighbor]);
scheduler.alertPropagator(neighbor);
};

return self;
}
}

function makeDefaultPropagators() {
self.pId = functionCallPropagator(requireAll(function (a) { return a }));
self.pNot = functionCallPropagator(requireAll(function (a) { return !a }));
self.pAdd = functionCallPropagator(requireAll(function (a, b) { return a + b }));
self.pSubtract = functionCallPropagator(requireAll(function (a, b) { return a - b }));
self.pMultiply = functionCallPropagator(requireAll(function (a, b) { return a * b }));
self.pDivide = functionCallPropagator(requireAll(function (a, b) { return a / b }));
self.pSwitch = functionCallPropagator(function (control, input) { if (control) return input });
self.pConditional = functionCallPropagator(function (control, consequent, alternate) { if (control) { return consequent } else { return alternate } });
// TODO: pConditionalRouter
// TODO: pDeposit
// TODO: pExamine
// TODO: pWhen (important!)
// (p:when internal-cells condition-cell body ...)
// when condition-cell is true,
// body: arbitrary collection of code, defining some amount of propagator network that will not be built until the controlling cell indicates that it should
// internal-cells: list of the free variables in body (kluge since can't detect free variables in Scheme)
// TODO: pIf

self.cId = self.Cell(function (scheduler, cells) {
scheduler.diagramApply(scheduler.pId, [cells[0], cells[1]]);
scheduler.diagramApply(scheduler.pId, [cells[1], cells[0]]);
});

self.cNot = self.Cell(function (scheduler, cells) {
scheduler.diagramApply(scheduler.pNot, [cells[0], cells[1]]);
scheduler.diagramApply(scheduler.pNot, [cells[1], cells[0]]);
});

self.cAdd = self.Cell(function (scheduler, cells) {
scheduler.diagramApply(scheduler.pAdd, [cells[0], cells[1], cells[2]]);
scheduler.diagramApply(scheduler.pSubtract, [cells[2], cells[1], cells[0]]);
scheduler.diagramApply(scheduler.pSubtract, [cells[2], cells[0], cells[1]]);
});
self.cSubtract = self.Cell(function (scheduler, cells) {
scheduler.diagramApply(scheduler.cAdd, [cells[1], cells[2], cells[0]]);
});

self.cMultiply = self.Cell(function (scheduler, cells) {
scheduler.diagramApply(scheduler.pMultiply, [cells[0], cells[1], cells[2]]);
scheduler.diagramApply(scheduler.pDivide, [cells[2], cells[1], cells[0]]);
scheduler.diagramApply(scheduler.pDivide, [cells[2], cells[0], cells[1]]);
});
self.cDivide = self.Cell(function (scheduler, cells) {
scheduler.diagramApply(scheduler.cMultiply, [cells[1], cells[2], cells[0]]);
});

function requireAll(f) {
return function () {
if (_.all(arguments, function (value) { return value != undefined })) {
return f.apply(this, arguments);
}
};
}

function functionCallPropagator(f) {
return self.Cell(function (scheduler, cells) {
var inputs = cells.slice(0, cells.length - 1);
var output = cells[cells.length - 1];
scheduler.addPropagator(inputs, toDo);

function toDo() {
var answer = f.apply(undefined, _.map(inputs, getContent));
output.addContent(answer);

function getContent(cell) {
return cell.content();
}
}
});
}
}
}

// function addCompoundPropagator(scheduler, neighbors, toBuild) {
// var done = false;
// scheduler.addPropagator(neighbors, toDo);

// function toDo() {
// if (!done) {
// if (_.any(neighbors, getContent)) {
// done = true;
// toBuild();
// }
// }

// function getContent(cell) {
// return cell.content();
// }
// }
// }

function merge(content, increment) {
if (increment == undefined) {
return content;
} else {
return increment; // TODO
}
}

function equivalent(a, b) {
return a === b;
}

exports.Scheduler = Scheduler;
21 changes: 21 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name" : "propagators",
"description" : "implementation of propagators http://groups.csail.mit.edu/mac/users/gjs/propagators/",
"license" : "MIT",
"author" : "Tom Lieber <[email protected]>",
"version" : "0.0.1",
"main" : "./index",
"repository" : {
"type" : "git",
"url" : "https://github.com/alltom/propagators.git"
},
"dependencies" : {
"underscore" : "~1.5.2"
},
"devDependencies" : {
"tap" : "~0.4.6"
},
"scripts" : {
"test" : "tap test/test-*.js"
}
}
Loading

0 comments on commit 85f4382

Please sign in to comment.