Robin:

http://dpaste.dzfl.pl/3df8694eb47d

I think it's better to improve your code iteratively. First starting with small simple things:


   this(size_t rows, size_t cols) nothrow pure {

=>

    this(in size_t rows, in size_t cols) nothrow pure {


   this(ref const(Dimension) that) nothrow pure {

=>

    this(const ref Dimension that) nothrow pure {


   ref Dimension opAssign(ref Dimension rhs) nothrow pure {

Is this method necessary?


   bool opEquals(ref const(Dimension) other) nothrow const {

Not necessary.


   size_t min() @property nothrow const {
       if (this.rows <= this.cols) return this.rows;
       else                        return this.cols;
   }

=> (I have changed its name to reduce my confusion std.algorithm.min):

    @property size_t minSide() const pure nothrow {
        return (rows <= cols) ? rows : cols;
    }


   size_t size() @property nothrow const {

=>

    @property size_t size() @property pure nothrow {


   size_t offset(size_t row, size_t col) nothrow const {

=>

size_t offset(in size_t row, in size_t col) const pure nothrow {



this(in size_t rows, in size_t cols, bool initialize = true) nothrow pure {
       this.dim = Dimension(rows, cols);
this.data = minimallyInitializedArray!(typeof(this.data))(rows * cols);
       if (initialize) this.data[] = to!T(0);
   }

=>

this(in size_t rows, in size_t cols, in bool initialize = true) nothrow pure {
    ...
    if (initialize)
        this.data[] = 0;


   /**
    *
    */

Sometimes I prefer to use just one line of code to reduce vertical wasted space:

/// Move constructor. From rvalue.


   this(ref const(Matrix) that) {

=>

    this(const ref Matrix that) pure {


       this.data = that.data.dup;

Currently array.dup is not nothrow. This will eventually be fixed.


   ref Matrix transpose() const {
       return Matrix(this).transposeAssign();

=>

    ref Matrix transpose() const pure nothrow {
        return Matrix(this).transposeAssign;


   ref Matrix transposeAssign() nothrow {
       size_t r, c;
       for (r = 0; r < this.dim.rows; ++r) {
           for (c = 0; c < r; ++c) {
               std.algorithm.swap(
                   this.data[this.dim.offset(r, c)],
                   this.data[this.dim.offset(c, r)]);
           }
       }
       return this;
   }

Use immutable foreach loops.
And even when you use for loops always define the loop variable inside the for: "for (size_t r = 0; ...".
Also in general I suggest you to write a little less code.

A first try (not tested), but probably this can be done with much less multiplications:

    ref Matrix transposeAssign() pure nothrow {
        foreach (immutable r; 0 .. dim.rows) {
            foreach (immutable c; 0 .. r) {
swap(data[dim.offset(r, c)], data[dim.offset(c, r)]);
            }
        }
        return this;
    }


   Matrix opMul(ref const(Matrix) other)

Never use old-style operator overloading in new D code. Use only the new operator overloading style.


       auto s = Matrix(other).transposeAssign();

=>

       auto s = Matrix(other).transposeAssign;


       size_t r1, r2, c;

Ditto.


       foreach (ref T element; this.data) {
           element *= scalar;
       }

Try to use:

        data[] *= scalar;


       for (auto i = 0; i < this.dim.size; ++i) {
           this.data[i] += other.data[i];
       }

Try to use:

        data[] += other.data[];


       for (auto i = 0; i < this.dim.size; ++i) {
           this.data[i] -= other.data[i];
       }

Try to use:

        data[] -= other.data[];


   bool opEquals(ref const(Matrix) other) nothrow const {
       if (this.dim != other.dim) {
           return false;
       }
       for (auto i = 0; i < this.dim.size; ++i) {
           if (this.data[i] != other.data[i]) return false;
       }
       return true;
   }

Try (in general try to write less code):

    return dim == other.dim && data == other.data;



       auto stringBuilder = std.array.appender!string;

=>

        Appender!string result;


       stringBuilder.put("Matrix: "
~ to!string(this.dim.rows) ~ " x " ~ to!string(this.dim.cols)

=>

        result ~= text("Matrix: ", dim.rows, " x ", dim.cols


       auto m = Matrix(rows, cols);
       for (auto i = 0; i < m.dim.min; ++i) {
           m[i, i] = 1;
       }

See the comment by John Colvin.


       auto generator = Random(unpredictableSeed);

What if I want to fill the matrix deterministically, with a given seed? In general it's better to not add a random matrix method to your matrix struct. Better to add an external free function that uses UFCS and is more flexible and simpler to reason about.



writeln("\tTime required: " ~ to!string(secs) ~ " secs, " ~ to!string(msecs) ~ " msecs");

Use .text to strinify, but here you don't need to stringify at all:

=>

writeln("\tTime required: ", secs, " secs, ", msecs, " msecs");


   sw.reset();

=>
    sw.reset;


void multiplicationTest() {

In D there is also unittest {}. A benchmark is not exactly an unit test, so do as you prefer.

Bye,
bearophile

Reply via email to