Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 3602a2792024d980fe261d34e289686b0c4985bd 0 parents
dimituri authored
4 .gitignore
@@ -0,0 +1,4 @@
+/build/
+/docs/
+/lib/
+/node_modules/
6 .npmignore
@@ -0,0 +1,6 @@
+.git*
+build/
+Cakefile
+docs/
+examples/
+src/
97 Cakefile
@@ -0,0 +1,97 @@
+fs = require 'fs'
+glob = require 'glob'
+matrices = require './src/matrices'
+path = require 'path'
+stitch = require 'stitch'
+uglify = require 'uglify-js'
+{exec} = require 'child_process'
+
+# Run the specified function if a given executable is installed,
+# or print a notice.
+ifInstalled = (executable, fn) ->
+ exec 'which ' + executable, (err) ->
+ return fn() unless err
+ console.log "This task needs `#{executable}' to be installed and in PATH."
+
+# Try to execute a shell command or fail with an error.
+tryExec = (cmd) ->
+ proc = exec cmd, (err) ->
+ throw err if err
+ proc.stdout.on 'data', (data) ->
+ process.stdout.write data.toString()
+
+# Safely make a directory with default permissions.
+makeDir = (dir) ->
+ fs.mkdirSync dir, 0755 unless path.existsSync dir
+
+# Source header for built files.
+header = """
+/**
+ * Node.js matrices #{matrices.VERSION} (browser bundle)
+ *
+ * Copyright (c) 2010-2011 Dimitry Solovyov
+ * Released under the MIT license
+ */
+
+"""
+
+# Source footer for built files.
+footer = "this.matrices = require('matrices');"
+
+# Compile all CoffeeScript sources.
+build = (watch) ->
+ ifInstalled 'coffee', ->
+ tryExec "rm -rf lib && coffee -cb#{if watch then 'w' else ''} -o lib src"
+
+# Compile all CoffeeScript sources for the browser.
+buildBrowser = ->
+ stitch
+ .createPackage
+ paths: [__dirname + '/src']
+ .compile (err, src) ->
+ throw err if err
+ makeDir 'build'
+ makeDir 'build/' + matrices.VERSION
+ dir = fs.realpathSync 'build/' + matrices.VERSION
+ fs.writeFileSync dir + '/pablo.js', header + src + footer
+ fs.writeFileSync dir + '/pablo.min.js', header + uglify(src + footer)
+ tryExec "rm -f build/edge && ln -s #{dir}/ build/edge"
+
+# Build task for Node.
+task 'build', 'Compile CoffeeScript source for Node.', ->
+ build()
+
+# Build task for browsers.
+task 'build:browser', 'Compile CoffeeScript source for browsers.', ->
+ buildBrowser()
+
+# Build task for both Node and browsers.
+task 'build:all', 'Compile CoffeeScript source for Node and browsers.', ->
+ build()
+ buildBrowser()
+
+# Dev task for Node and browsers.
+task 'dev', 'Build everything once, then watch for changes.', ->
+ build true
+ for file in glob.globSync 'src/**/*.coffee'
+ fs.watchFile file, {persistent: true, interval: 500}, (curr, prev) ->
+ if curr.mtime isnt prev.mtime
+ buildBrowser()
+
+# Generate documentation files using Docco.
+task 'docs', 'Generate documentation files.', ->
+ ifInstalled 'docco', ->
+ tryExec 'docco src/*.coffee src/matrices/*.coffee'
+
+# Remove build and lib directories to allow for a clean build
+# or just tidy things up.
+task 'clean', 'Take care of the compilation aftermath.', ->
+ tryExec 'rm -rf {build,lib}'
+
+# Remove docs directory, if this is ever needed.
+task 'clean:docs', 'Clean the generated documentation files.', ->
+ tryExec 'rm -rf docs'
+
+# Remove build, docs, and lib directories altogether.
+task 'clean:all', 'Clean both the build file and the docs.', ->
+ tryExec 'rm -rf {build,docs,lib}'
19 LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2010-2011 Dimitry Solovyov
+
+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.
5 README.md
@@ -0,0 +1,5 @@
+# Matrices for Node
+
+Do this:
+
+ $ npm install matrices
20 package.json
@@ -0,0 +1,20 @@
+{
+ "author": "Dimitry Solovyov <dimituri@gmail.com> (http://100-hour.com)",
+ "name": "matrices",
+ "description": "Classes for matrix calculations.",
+ "version": "0.1.0",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/dimituri/node-matrices.git"
+ },
+ "main": "lib/matrices",
+ "engines": {
+ "node": "~0.4.10"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "coffee-script": "~1.1.1",
+ "glob": "~2.0.7",
+ "uglify-js": "~1.0.6"
+ }
+}
3  src/matrices.coffee
@@ -0,0 +1,3 @@
+module.exports =
+ VERSION: '0.1.0'
+ Matrix: require './matrices/matrix.coffee'
138 src/matrices/matrix.coffee
@@ -0,0 +1,138 @@
+module.exports = class Matrix
+ constructor: (rows, cols, items = []) ->
+ @rows = rows
+ @cols = cols
+ @items = items
+
+ @identity: (n) ->
+ items = []
+ for i in [0...n]
+ for j in [0...n]
+ items.push if i is j then 1 else 0
+ new Matrix n, n, items
+
+ index: (i, j) ->
+ i * @cols + j
+
+ get: (i, j) ->
+ @items[@index i, j]
+
+ project: (fns...) ->
+ items = []
+ for row in [0...@rows]
+ for fn in fns
+ ind = row * @cols
+ items.push fn(@items.slice(ind, ind + @cols))
+ new Matrix @rows, fns.length, items
+
+ @column: (n) ->
+ (arr) -> arr[n]
+
+ proj: @::project
+
+ transpose: ->
+ items = []
+ for i in [0...@rows]
+ for j in [0...@cols]
+ items.push @items[j * @rows + i]
+ new Matrix @cols, @rows, items
+
+ transp: @::transpose
+ t: @::transpose
+
+ clone: ->
+ new Matrix @rows, @cols, @items.slice(0)
+
+ inverse: ->
+ if @rows isnt @cols
+ throw new Error 'Dimensionality mismatch'
+ m = @clone()
+ size = @rows
+ row = (i for i in [0...size] by 1)
+ inv = Matrix.identity size
+ for i in [0...size] by 1
+ lead = i
+ leadVal = m.get row[lead], i
+ for j in [i + 1...size] by 1
+ test = j
+ testVal = m.get row[test], i
+ if Math.abs(testVal) > Math.abs(leadVal)
+ leadVal = testVal
+ lead = j
+ temp = row[i]
+ row[i] = row[lead]
+ row[lead] = temp
+ for j in [0...size] by 1
+ ind = m.index row[i], j
+ m.items[ind] /= leadVal
+ inv.items[ind] /= leadVal
+ for ii in [i + 1...size] by 1
+ k = m.get row[ii], i
+ for j in [0...size] by 1
+ ind = m.index row[ii], j
+ m.items[ind] -= k * m.get(row[i], j)
+ inv.items[ind] -= k * inv.get(row[i], j)
+ for i in [size - 1..0] by -1
+ for ii in [i - 1..0] by -1
+ k = m.get row[ii], i
+ for j in [0...size] by 1
+ ind = m.index row[ii], j
+ m.items[ind] -= k * m.get(row[i], j)
+ inv.items[ind] -= k * inv.get(row[i], j)
+ res = new Matrix size, size
+ for i in [0...size] by 1
+ for j in [0...size] by 1
+ res.items[res.index i, j] = inv.items[inv.index row[i], j]
+ res
+
+ inv: @::inverse
+
+ negate: ->
+ new Matrix @rows, @cols, (-item for item in @items)
+
+ neg: @::negate
+
+ add: (other) ->
+ if @rows isnt other.rows or @cols isnt other.cols
+ throw new Error 'Dimensionality mismatch'
+ items = []
+ for i in [0...@items.length]
+ items.push @items[i] + other.items[i]
+ new Matrix @rows, @cols, items
+
+ subtract: (other) ->
+ @add other.neg()
+
+ sub: @::subtract
+
+ multiply: (other) ->
+ if @cols isnt other.rows
+ throw new Error 'Dimensionality mismatch'
+ items = []
+ for i in [0...@rows]
+ for j in [0...other.cols]
+ sum = 0
+ for k in [0...@cols]
+ sum += @get(i, k) * other.get(k, j)
+ items[i * other.cols + j] = sum
+ new Matrix @rows, other.cols, items
+
+ mul: @::multiply
+
+ divide: (other) ->
+ @mul other.inverse()
+
+ div: @::divide
+
+ norm: ->
+ norm = 0
+ norm += item * item for item in @items
+ norm
+
+ toString: ->
+ s = ''
+ for row in [0...@rows] by 1
+ ind = row * @cols
+ items = (item.toFixed(2) for item in @items.slice(ind, ind + @cols))
+ s += items.join(', ') + "\n"
+ s
Please sign in to comment.
Something went wrong with that request. Please try again.