Skip to content

Instantly share code, notes, and snippets.

@OverlappingElvis
Last active August 17, 2017 20:31
Show Gist options
  • Save OverlappingElvis/232b2a4b5e94e3a8aa60471655c84a1f to your computer and use it in GitHub Desktop.
Save OverlappingElvis/232b2a4b5e94e3a8aa60471655c84a1f to your computer and use it in GitHub Desktop.

Revisions

  1. OverlappingElvis revised this gist Aug 17, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bathroom.js
    Original file line number Diff line number Diff line change
    @@ -101,4 +101,4 @@ var fn = results.falseNegative / samples;
    // Reporting
    console.log('Results after ' + numberOfRuns + ' runs:');
    console.log('Probability of the bathroom being occupied when the sign reads occupied: ' + (tp / (tp + fp)).toPrecision(4));
    console.log('Probability of the bathroom being occupied when the sign reads occupied: ' + (tn / (tn + fn)).toPrecision(4));
    console.log('Probability of the bathroom being vacant when the sign reads vacant: ' + (tn / (tn + fn)).toPrecision(4));
  2. OverlappingElvis revised this gist Aug 17, 2017. 1 changed file with 8 additions and 5 deletions.
    13 changes: 8 additions & 5 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -69,7 +69,7 @@ Person.prototype.useBathroom = function(state) {
    };

    // Set number of runs for the model
    var numberOfRuns = 100000;
    var numberOfRuns = 500000;
    // Sample twice per run
    var samples = numberOfRuns * 2;

    @@ -93,9 +93,12 @@ var results = _(numberOfRuns).chain()
    .reduce(function(state, person) { return person.useBathroom(state); }, initialState)
    .value();

    var tp = results.truePositive / samples;
    var tn = results.trueNegative / samples;
    var fp = results.falsePositive / samples;
    var fn = results.falseNegative / samples;

    // Reporting
    console.log('Results after ' + numberOfRuns + ' runs:');
    console.log('True positive probability: ' + results.truePositive / samples);
    console.log('True negative probability: ' + results.trueNegative / samples);
    console.log('False positive probability: ' + results.falsePositive / samples);
    console.log('False negative probability: ' + results.falseNegative / samples);
    console.log('Probability of the bathroom being occupied when the sign reads occupied: ' + (tp / (tp + fp)).toPrecision(4));
    console.log('Probability of the bathroom being occupied when the sign reads occupied: ' + (tn / (tn + fn)).toPrecision(4));
  3. OverlappingElvis revised this gist Aug 10, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion bathroom.js
    Original file line number Diff line number Diff line change
    @@ -97,5 +97,5 @@ var results = _(numberOfRuns).chain()
    console.log('Results after ' + numberOfRuns + ' runs:');
    console.log('True positive probability: ' + results.truePositive / samples);
    console.log('True negative probability: ' + results.trueNegative / samples);
    console.log('True negative probability: ' + results.falsePositive / samples);
    console.log('False positive probability: ' + results.falsePositive / samples);
    console.log('False negative probability: ' + results.falseNegative / samples);
  4. OverlappingElvis revised this gist Aug 10, 2017. No changes.
  5. OverlappingElvis revised this gist Aug 10, 2017. 1 changed file with 15 additions and 11 deletions.
    26 changes: 15 additions & 11 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -7,8 +7,12 @@ var VACANT = false;

    // Sample a current state
    var knock = function(state) {
    if (state.sign === state.bathroom) {
    return _({}).extend(state, { correct: state.correct + 1 });
    var correct = state.sign === state.bathroom;
    if (correct && state.sign === OCCUPIED) {
    return _({}).extend(state, { truePositive: state.truePositive + 1 });
    }
    if (correct && state.sign === VACANT) {
    return _({}).extend(state, { trueNegative: state.trueNegative + 1 });
    }
    if (state.sign && !state.bathroom) {
    return _({}).extend(state, { falsePositive: state.falsePositive + 1 });
    @@ -57,7 +61,6 @@ Person.prototype.enterBathroom = function(state) {
    Person.prototype.exitBathroom = function(state) {
    return this.exitBehavior(state);
    };
    // Use the bathroom and sample each step
    Person.prototype.useBathroom = function(state) {
    // Enter the bathroom and sample the result
    var enterState = knock(this.enterBathroom(state));
    @@ -66,14 +69,16 @@ Person.prototype.useBathroom = function(state) {
    };

    // Set number of runs for the model
    var numberOfRuns = 50000;
    var numberOfRuns = 100000;
    // Sample twice per run
    var samples = numberOfRuns * 2;
    // Initial state

    // Initial starting state
    var initialState = {
    sign: VACANT,
    bathroom: VACANT,
    correct: 0,
    truePositive: 0,
    trueNegative: 0,
    falsePositive: 0,
    falseNegative: 0
    };
    @@ -85,13 +90,12 @@ var results = _(numberOfRuns).chain()
    // Generate as many people as runs
    .map(function() { return new Person(); })
    // Work through the runs, returning a final state
    .reduce(function(state, person) {
    return person.useBathroom(state);
    }, initialState)
    .reduce(function(state, person) { return person.useBathroom(state); }, initialState)
    .value();

    // Reporting
    console.log('Results after ' + numberOfRuns + ' runs:');
    console.log('Correct sign probability: ' + results.correct / samples);
    console.log('False positive probability: ' + results.falsePositive / samples);
    console.log('True positive probability: ' + results.truePositive / samples);
    console.log('True negative probability: ' + results.trueNegative / samples);
    console.log('True negative probability: ' + results.falsePositive / samples);
    console.log('False negative probability: ' + results.falseNegative / samples);
  6. OverlappingElvis revised this gist Aug 9, 2017. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -85,8 +85,8 @@ var results = _(numberOfRuns).chain()
    // Generate as many people as runs
    .map(function() { return new Person(); })
    // Work through the runs, returning a final state
    .reduce(function(memo, person) {
    return person.useBathroom(memo);
    .reduce(function(state, person) {
    return person.useBathroom(state);
    }, initialState)
    .value();

  7. OverlappingElvis revised this gist Aug 9, 2017. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -69,8 +69,7 @@ Person.prototype.useBathroom = function(state) {
    var numberOfRuns = 50000;
    // Sample twice per run
    var samples = numberOfRuns * 2;

    // Initial starting state
    // Initial state
    var initialState = {
    sign: VACANT,
    bathroom: VACANT,
  8. OverlappingElvis revised this gist Aug 9, 2017. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -84,9 +84,7 @@ var results = _(numberOfRuns).chain()
    // Get a list with length numberOfRuns
    .range()
    // Generate as many people as runs
    .map(function() {
    return new Person();
    })
    .map(function() { return new Person(); })
    // Work through the runs, returning a final state
    .reduce(function(memo, person) {
    return person.useBathroom(memo);
  9. OverlappingElvis revised this gist Aug 9, 2017. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -57,6 +57,7 @@ Person.prototype.enterBathroom = function(state) {
    Person.prototype.exitBathroom = function(state) {
    return this.exitBehavior(state);
    };
    // Use the bathroom and sample each step
    Person.prototype.useBathroom = function(state) {
    // Enter the bathroom and sample the result
    var enterState = knock(this.enterBathroom(state));
  10. OverlappingElvis revised this gist Aug 9, 2017. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion bathroom.js
    Original file line number Diff line number Diff line change
    @@ -94,7 +94,6 @@ var results = _(numberOfRuns).chain()

    // Reporting
    console.log('Results after ' + numberOfRuns + ' runs:');
    console.log(results);
    console.log('Correct sign probability: ' + results.correct / samples);
    console.log('False positive probability: ' + results.falsePositive / samples);
    console.log('False negative probability: ' + results.falseNegative / samples);
  11. OverlappingElvis revised this gist Aug 9, 2017. No changes.
  12. OverlappingElvis created this gist Aug 9, 2017.
    100 changes: 100 additions & 0 deletions bathroom.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,100 @@
    // underscore.js helpers
    var _ = require('underscore');

    // State aliases
    var OCCUPIED = true;
    var VACANT = false;

    // Sample a current state
    var knock = function(state) {
    if (state.sign === state.bathroom) {
    return _({}).extend(state, { correct: state.correct + 1 });
    }
    if (state.sign && !state.bathroom) {
    return _({}).extend(state, { falsePositive: state.falsePositive + 1 });
    }
    return _({}).extend(state, { falseNegative: state.falseNegative + 1 });
    };

    // Define behaviors as modifying the current state of the bathroom. Can be invoked as entering or exiting.

    // Don't change the state of the sign
    var unobservant = function(state, exit) {
    return _({}).extend(state, {
    sign: state.sign,
    bathroom: !exit
    });
    };
    // Change the sign when entering, but not on leaving
    var forgetful = function(state, exit) {
    return _({}).extend(state, {
    sign: OCCUPIED,
    bathroom: !exit
    });
    };
    // Make sure that the sign reflects the actual state of the bathroom
    var conscientious = function(state, exit) {
    return _({}).extend(state, {
    sign: !exit,
    bathroom: !exit
    });
    };
    // Each behavior is as likely to appear
    var chooseBehavior = _(_.sample).partial([unobservant, forgetful, conscientious]);

    // Create a person, randomly choosing a behavior
    var Person = function() {
    var behavior = chooseBehavior();
    this.enterBehavior = behavior;
    // Behavior functionality is based on the exit flag, so we can reuse and partially apply that flag to the exit behavior
    this.exitBehavior = _(behavior).partial(_, true);
    };
    // Enter bathroom
    Person.prototype.enterBathroom = function(state) {
    return this.enterBehavior(state);
    };
    // Exit bathroom
    Person.prototype.exitBathroom = function(state) {
    return this.exitBehavior(state);
    };
    Person.prototype.useBathroom = function(state) {
    // Enter the bathroom and sample the result
    var enterState = knock(this.enterBathroom(state));
    // Exit the bathroom and sample the result
    return knock(this.exitBathroom(enterState));
    };

    // Set number of runs for the model
    var numberOfRuns = 50000;
    // Sample twice per run
    var samples = numberOfRuns * 2;

    // Initial starting state
    var initialState = {
    sign: VACANT,
    bathroom: VACANT,
    correct: 0,
    falsePositive: 0,
    falseNegative: 0
    };

    // Get the results
    var results = _(numberOfRuns).chain()
    // Get a list with length numberOfRuns
    .range()
    // Generate as many people as runs
    .map(function() {
    return new Person();
    })
    // Work through the runs, returning a final state
    .reduce(function(memo, person) {
    return person.useBathroom(memo);
    }, initialState)
    .value();

    // Reporting
    console.log('Results after ' + numberOfRuns + ' runs:');
    console.log(results);
    console.log('Correct sign probability: ' + results.correct / samples);
    console.log('False positive probability: ' + results.falsePositive / samples);
    console.log('False negative probability: ' + results.falseNegative / samples);