diff --git a/.gitignore b/.gitignore index 7d378c2..27736ea 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ coffeescript/node_modules/* java/build/* java/.gradle/* .sass-cache/* +npm-debug.log +docs/* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4a18a95 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Dylon Edwards + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/coffeescript/Cakefile b/coffeescript/Cakefile new file mode 100644 index 0000000..8bcff79 --- /dev/null +++ b/coffeescript/Cakefile @@ -0,0 +1,37 @@ +require 'coffee-script/register' #-> Register the .coffee extension + +fs = require 'fs' +{print} = require 'sys' +{spawn, exec} = require 'child_process' + +build = (watch, callback) -> + if typeof watch is 'function' + callback = watch + watch = false + options = ['-b', '-c', '-o', 'lib', 'src'] + options.unshift '-w' if watch + + coffee = spawn 'coffee', options + coffee.stdout.on 'data', (data) -> print data.toString() + coffee.stderr.on 'data', (data) -> print data.toString() + coffee.on 'exit', (status) -> callback?() if status is 0 + +task 'docs', 'Generate annotated source code with Docco', -> + fs.readdir 'src', (err, contents) -> + files = ("src/#{file}" for file in contents when /\.coffee$/.test file) + docco = spawn 'docco', files + docco.stdout.on 'data', (data) -> print data.toString() + docco.stderr.on 'data', (data) -> print data.toString() + docco.on 'exit', (status) -> callback?() if status is 0 + +task 'build', 'Compile CoffeeScript source files', -> + build() + +task 'watch', 'Recompile CoffeeScript source files when modified', -> + build true + +task 'test', 'Run the test suite', -> + build -> + {reporters} = require 'nodeunit' + process.chdir __dirname + reporters.default.run ['test'] diff --git a/coffeescript/lib/permutation.js b/coffeescript/lib/permutation.js new file mode 100644 index 0000000..3cbc4ff --- /dev/null +++ b/coffeescript/lib/permutation.js @@ -0,0 +1,14 @@ +// Generated by CoffeeScript 1.7.1 +var permutation; + +permutation = function(list, index) { + if (list.length - index === 0) { + return []; + } else if (list.length - index === 1) { + return [list.slice()]; + } +}; + +exports.permutation = function(list) { + return permutation(list, 0); +}; diff --git a/coffeescript/lib/permutations.js b/coffeescript/lib/permutations.js new file mode 100644 index 0000000..0e99abe --- /dev/null +++ b/coffeescript/lib/permutations.js @@ -0,0 +1,58 @@ +// Generated by CoffeeScript 1.7.1 +var concat, expand, global, permutations, swap, + __slice = [].slice; + +global = typeof exports === 'object' ? exports : typeof window === 'object' ? window : this; + +concat = function() { + var concatenation, list, lists, _i, _len; + lists = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + concatenation = []; + for (_i = 0, _len = lists.length; _i < _len; _i++) { + list = lists[_i]; + concatenation = concatenation.concat(list); + } + return concatenation; +}; + +expand = function(element, lists) { + var list, _i, _len; + for (_i = 0, _len = lists.length; _i < _len; _i++) { + list = lists[_i]; + list.unshift(element); + } + return lists; +}; + +swap = function(list, i, j) { + var t; + t = list[i]; + list[i] = list[j]; + list[j] = t; + return list; +}; + +permutations = function(list, i) { + var j, l, offset, p, _i; + switch (list.length - i) { + case 0: + return []; + case 1: + return [[list[i]]]; + case 2: + return [[list[i], list[i + 1]], [list[i + 1], list[i]]]; + default: + p = []; + offset = list.length - i; + for (j = _i = 0; 0 <= offset ? _i < offset : _i > offset; j = 0 <= offset ? ++_i : --_i) { + l = list.slice(); + swap(l, i, i + j); + p.push(expand(l[i], permutations(l, i + 1))); + } + return concat.apply(null, p); + } +}; + +global.permutations = function(list) { + return permutations(list, 0); +}; diff --git a/coffeescript/package.json b/coffeescript/package.json new file mode 100644 index 0000000..07daa08 --- /dev/null +++ b/coffeescript/package.json @@ -0,0 +1,25 @@ +{ + "name": "liblevenshtein", + "description": "Various utilities regarding Levenshtein transducers.", + "author": "Dylon Edwards", + "version": "2.0.0", + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/dylon/liblevenshtein/raw/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/dylon/liblevenshtein.git" + }, + "main": null, + "devDependencies": { + "nodeunit": "~0.8", + "coffee-script": "~1.7" + }, + "engines": + { + "node": "~0.10" + } +} diff --git a/coffeescript/src/permutations.coffee b/coffeescript/src/permutations.coffee new file mode 100644 index 0000000..bf78681 --- /dev/null +++ b/coffeescript/src/permutations.coffee @@ -0,0 +1,44 @@ +global = + if typeof exports is 'object' + exports + else if typeof window is 'object' + window + else + this + +concat = (lists...) -> + concatenation = [] + (concatenation = concatenation.concat(list)) for list in lists + concatenation + +expand = (element, lists) -> + list.unshift(element) for list in lists + lists + +swap = (list, i, j) -> + t = list[i] + list[i] = list[j] + list[j] = t + list + +permutations = (list, i) -> + switch list.length - i + when 0 + [] + when 1 + [[list[i]]] + when 2 + [ + [list[i], list[i + 1]] + [list[i + 1], list[i]] + ] + else + p = [] + offset = list.length - i + for j in [0...offset] + l = list.slice() + swap(l, i, i + j) + p.push(expand(l[i], permutations(l, i + 1))) + concat.apply(null, p) + +global.permutations = (list) -> permutations(list, 0) diff --git a/coffeescript/test/permutations.coffee b/coffeescript/test/permutations.coffee new file mode 100644 index 0000000..35e95be --- /dev/null +++ b/coffeescript/test/permutations.coffee @@ -0,0 +1,178 @@ +{permutations} = require '../src/permutations' + +module.exports = + 'There should be no permutations on an empty list': (test) -> + test.deepEqual(permutations([]), []) + test.done() + 'The only permutation on a singleton list should be the same list': (test) -> + test.deepEqual(permutations([1]), [[1]]) + test.done() + 'There should be 2-factorial, distinct permutations on a pair': (test) -> + test.deepEqual(permutations([1,2]),[ + [1,2] + [2,1] + ]) + test.done() + 'There should be 3-factorial, distinct permutations on a triple': (test) -> + test.deepEqual(permutations([1..3]), [ + [1, 2, 3] + [1, 3, 2] + [2, 1, 3] + [2, 3, 1] + [3, 2, 1] + [3, 1, 2] + ]) + test.done() + 'There should be 4-factorial, distinct permutations on a quadruple': (test) -> + test.deepEqual(permutations([1..4]), [ + [1, 2, 3, 4] + [1, 2, 4, 3] + [1, 3, 2, 4] + [1, 3, 4, 2] + [1, 4, 3, 2] + [1, 4, 2, 3] + [2, 1, 3, 4] + [2, 1, 4, 3] + [2, 3, 1, 4] + [2, 3, 4, 1] + [2, 4, 3, 1] + [2, 4, 1, 3] + [3, 2, 1, 4] + [3, 2, 4, 1] + [3, 1, 2, 4] + [3, 1, 4, 2] + [3, 4, 1, 2] + [3, 4, 2, 1] + [4, 2, 3, 1] + [4, 2, 1, 3] + [4, 3, 2, 1] + [4, 3, 1, 2] + [4, 1, 3, 2] + [4, 1, 2, 3] + ]) + test.done() + 'There should be 5-factorial, distinct permutations on a 5-tuple': (test) -> + test.deepEqual(permutations([1..5]), [ + [1, 2, 3, 4, 5] + [1, 2, 3, 5, 4] + [1, 2, 4, 3, 5] + [1, 2, 4, 5, 3] + [1, 2, 5, 4, 3] + [1, 2, 5, 3, 4] + [1, 3, 2, 4, 5] + [1, 3, 2, 5, 4] + [1, 3, 4, 2, 5] + [1, 3, 4, 5, 2] + [1, 3, 5, 4, 2] + [1, 3, 5, 2, 4] + [1, 4, 3, 2, 5] + [1, 4, 3, 5, 2] + [1, 4, 2, 3, 5] + [1, 4, 2, 5, 3] + [1, 4, 5, 2, 3] + [1, 4, 5, 3, 2] + [1, 5, 3, 4, 2] + [1, 5, 3, 2, 4] + [1, 5, 4, 3, 2] + [1, 5, 4, 2, 3] + [1, 5, 2, 4, 3] + [1, 5, 2, 3, 4] + [2, 1, 3, 4, 5] + [2, 1, 3, 5, 4] + [2, 1, 4, 3, 5] + [2, 1, 4, 5, 3] + [2, 1, 5, 4, 3] + [2, 1, 5, 3, 4] + [2, 3, 1, 4, 5] + [2, 3, 1, 5, 4] + [2, 3, 4, 1, 5] + [2, 3, 4, 5, 1] + [2, 3, 5, 4, 1] + [2, 3, 5, 1, 4] + [2, 4, 3, 1, 5] + [2, 4, 3, 5, 1] + [2, 4, 1, 3, 5] + [2, 4, 1, 5, 3] + [2, 4, 5, 1, 3] + [2, 4, 5, 3, 1] + [2, 5, 3, 4, 1] + [2, 5, 3, 1, 4] + [2, 5, 4, 3, 1] + [2, 5, 4, 1, 3] + [2, 5, 1, 4, 3] + [2, 5, 1, 3, 4] + [3, 2, 1, 4, 5] + [3, 2, 1, 5, 4] + [3, 2, 4, 1, 5] + [3, 2, 4, 5, 1] + [3, 2, 5, 4, 1] + [3, 2, 5, 1, 4] + [3, 1, 2, 4, 5] + [3, 1, 2, 5, 4] + [3, 1, 4, 2, 5] + [3, 1, 4, 5, 2] + [3, 1, 5, 4, 2] + [3, 1, 5, 2, 4] + [3, 4, 1, 2, 5] + [3, 4, 1, 5, 2] + [3, 4, 2, 1, 5] + [3, 4, 2, 5, 1] + [3, 4, 5, 2, 1] + [3, 4, 5, 1, 2] + [3, 5, 1, 4, 2] + [3, 5, 1, 2, 4] + [3, 5, 4, 1, 2] + [3, 5, 4, 2, 1] + [3, 5, 2, 4, 1] + [3, 5, 2, 1, 4] + [4, 2, 3, 1, 5] + [4, 2, 3, 5, 1] + [4, 2, 1, 3, 5] + [4, 2, 1, 5, 3] + [4, 2, 5, 1, 3] + [4, 2, 5, 3, 1] + [4, 3, 2, 1, 5] + [4, 3, 2, 5, 1] + [4, 3, 1, 2, 5] + [4, 3, 1, 5, 2] + [4, 3, 5, 1, 2] + [4, 3, 5, 2, 1] + [4, 1, 3, 2, 5] + [4, 1, 3, 5, 2] + [4, 1, 2, 3, 5] + [4, 1, 2, 5, 3] + [4, 1, 5, 2, 3] + [4, 1, 5, 3, 2] + [4, 5, 3, 1, 2] + [4, 5, 3, 2, 1] + [4, 5, 1, 3, 2] + [4, 5, 1, 2, 3] + [4, 5, 2, 1, 3] + [4, 5, 2, 3, 1] + [5, 2, 3, 4, 1] + [5, 2, 3, 1, 4] + [5, 2, 4, 3, 1] + [5, 2, 4, 1, 3] + [5, 2, 1, 4, 3] + [5, 2, 1, 3, 4] + [5, 3, 2, 4, 1] + [5, 3, 2, 1, 4] + [5, 3, 4, 2, 1] + [5, 3, 4, 1, 2] + [5, 3, 1, 4, 2] + [5, 3, 1, 2, 4] + [5, 4, 3, 2, 1] + [5, 4, 3, 1, 2] + [5, 4, 2, 3, 1] + [5, 4, 2, 1, 3] + [5, 4, 1, 2, 3] + [5, 4, 1, 3, 2] + [5, 1, 3, 4, 2] + [5, 1, 3, 2, 4] + [5, 1, 4, 3, 2] + [5, 1, 4, 2, 3] + [5, 1, 2, 4, 3] + [5, 1, 2, 3, 4] + ]) + test.done() +