/** * Simple matrix multiplier with shake * * Authors: * Gregor Richards * * License: * Copyright (c) 2007 Gregor Richards * * 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. */ module shakematrix; import tango.io.Stdout; import tango.stdc.stdlib; import shake.Actor; import shake.Message; class Matrix { public: this(real[] sv, int sw, int sh) { v = sv.dup; while (v.length < sw * sh) v ~= 0.0; _w = sw; _h = sh; } /** Get a value out of the matrix */ real opIndex(int x, int y) { assert(x >= 0 && x < w && y >= 0 && y < h); return v[w*y + x]; } /** Set a value into the matrix */ void opIndexAssign(real sv, int x, int y) { assert(x >= 0 && x < w && y >= 0 && y < h); v[w*y + x] = sv; } /** Accessor */ int w() { return _w; } /** ditto */ void w(int sw) { _w = sw; } /** ditto */ int h() { return _h; } /** ditto */ void h(int sh) { _h = sh; } private: real[] v; int _w, _h; } /** The actor that receives all of the multiplied matrix values */ class MatrixMultiplier : Actor { public: this (Matrix sl, Matrix sr) { assert(sl.w == sr.h); l = sl; r = sr; res = new Matrix([], sr.w, sl.h); togo = sr.w * sl.h; } Matrix l, r, res; int togo; } /** The message that tells the matrix multiplier to start multiplying matrices */ class MatrixMultiply : Message { public: void handle(Actor a) { auto mm = cast(MatrixMultiplier) a; assert(mm !is null); // create five node multipliers Actor[] nms; for (int i = 0; i < 5; i++) { Actor nm = new Actor; nms ~= nm; nm.start(); } // and a delegater to manage them Delegater d = new Delegater(nms); // then send messages for each row and column for (int y = 0; y < mm.res.w; y++) { for (int x = 0; x < mm.res.h; x++) { d.enqueue(new CellMultiply(mm, mm.l, mm.r, x, y)); } } d.start(); } } /** The message to generate the value for a cell */ class CellMultiply : Message { public: this(Actor ssender, Matrix sl, Matrix sr, int sx, int sy) { super(ssender); l = sl; r = sr; x = sx; y = sy; } void handle(Actor a) { real res = 0; // go element-by-element for (int i = 0; i < l.w; i++) { res += l[i, y] * r[x, i]; } // now send the message back to the host sender.enqueue(new CellSet(x, y, res)); } private: Matrix l, r; int x, y; } /** The message to set a cell */ class CellSet : Message { public: this(int sx, int sy, real sv) { x = sx; y = sy; v = sv; } void handle(Actor a) { auto mm = cast(MatrixMultiplier) a; assert(mm !is null); // set it mm.res[x, y] = v; mm.togo--; // if we have no more to go, we're done if (mm.togo == 0) { synchronized (Stdout) { for (int y = 0; y < mm.res.h; y++) { for (int x = 0; x < mm.res.w; x++) { Stdout(mm.res[x, y])(" "); } Stdout.newline; } } exit(0); } } private: int x, y; real v; } int main() { MatrixMultiplier mm = new MatrixMultiplier( new Matrix( [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ], 5, 4), new Matrix( [ 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ], 4, 5)); mm.start(); mm.enqueueSync(new MatrixMultiply); return 0; }