help me learn to read documentation
Hi. I like to learn programming by examples but I need help learning how to read documentation. I have some idea of how it works in some aspects but in others i get completely stuck because there are no examples or code snippets. I am using dgame (dgame-dev.de) and im reading the documentation for changing the background text of my font in my program. I have the basic code for font creation but i need to make changes to the colors. import std.stdio; import std.system; import Dgame.System; import Dgame.Window; import Dgame.Graphic; import Dgame.Audio; import Dgame.Math; void main() { Font dejavu = Font("resources/dejavu.ttf", 12); Text CurrentFps = new Text(dejavu); ..window loop } The documentation here (http://dgame-dev.de/index.php?controller=learn=package=graphic=Text=0.6)... gives me the Text() class but i dont know how to use "foreground, background, and Font mode" or at least turn it into usable syntax.
Re: help me learn to read documentation
On Friday, 2 October 2015 at 01:20:50 UTC, Adam D. Ruppe wrote: On Thursday, 1 October 2015 at 19:15:39 UTC, Robin wrote: [...] Those describe simple class members, so you can set them through assignment: Text CurrentFps = new Text(dejavu); // change to white on black CurrentFps.foreground = Color4b.White; CurrentFps.background = Color4b.Black; // change mode CurrentFps.mode = Font.Mode.Shaded; I haven't actually used this library, but since the doc describes it with variable syntax (`Color4b foreground;`) that means you should be able to just assign to them like ordinary object member variables. Wow, thank you so much. I have never seen code like that before but the documentation there made me scratch my head. Thank you.
Rational of some DMD decisions
Hiho, as I am currently very insterested in compiler implementation I often look into the DMD github and look how things are done there. Often I find myself curious about things at first but find out the rational behind certain implementation decisions. One thing I can't figure out is the different approach with pre- and postfix expressions. While prefix expressions inherit from UnaExp (unary expression) which makes sense to me as it is an expression with only one parameter (in general) the postfix inc and decrement expressions are inherited from BinExpr (binary expression) which define their second expression to be an integer expression with a value of 1. So I am very curious about the rational behind this design decision. Why do Postfix expression not inherit from UnaExp, too? Am I missing something very important? Thanks in advance! =) I hope this is the right place to ask questions about the DMD compiler. Regards, Robin
Re: Rational of some DMD decisions
Thank you for your reply. I didn't know that it isn't possible to overload the post-inc and decrement operators in Dlang but I think I don't even miss this feature if pre-inc/dec is still available. =)
Re: Code doesn't work - why?
Hiho, thank you for your response on my topic. However, I still do not understand why it didn't work for struct value types since I do not perform any mutations on the state objects during execution of the code. The only thing happening with them is that they are getting copied bitwise and thus should have the same entries in the associative array as the original source, or am I wrong with this? When value types are copied bitwise then the associative array should also be copied that way or at least point to the same mapping as the source and thus shouldn't be empty after copying. What changes are required in order to make it work with struct value types as well? I even tried to change getNext to work with pointer return values instead but that did not help either. Regards, Rob
Re: Code doesn't work - why?
Hiho, thank you for your response! You just showed me my flaws while programming with value types. I think the only close solution is to work with pointers to the created states within the associative array instead of direct value types. Thanks for clearing this up to me. =) Regards, Rob
Re: Code doesn't work - why?
Here is the fully working code for everyone experiencing similar bugs or problems with pointers and value types. =) struct DeterministicState { public: this(string name, bool isFinal, DeterministicState *[char] transits...) { this.name = name; this.finalState = isFinal; this.addTransits(transits); } this(string name, bool isFinal) { this.name = name; this.finalState = isFinal; } this(bool isFinal, DeterministicState *[char] transits...) { this(, isFinal, transits); } this(DeterministicState *[char] transits...) { this(, false, transits); } void addTransits(DeterministicState *[char] newTransits) { foreach (immutable key; newTransits.keys) { transits[key] = newTransits[key]; } } string getName() const { return name; } bool isFinalState() const { return finalState; } bool hasNext(char input) const { return (input in transits) ? true : false; } DeterministicState * getNext(char input) { return transits[input]; } string toString() const { return name; } private: string name; DeterministicState *[char] transits; bool finalState; } struct DeterministicFiniteAutomaton { public: DeterministicState *[] input(char[] input) { DeterministicState *[] trace = [ start ]; auto currentState = trace[0]; foreach (immutable c; input) { if (!currentState.hasNext(c)) { writeln(currentState.toString() ~ has no next for ~ to!string(c)); break; } else { writeln(currentState.toString() ~ has next for ~ to!string(c)); } currentState = currentState.getNext(c); trace ~= currentState; } return trace; } this(DeterministicState * start) { this.start = start; } private: DeterministicState * start; } void main() { auto s0 = DeterministicState(s0, false); auto s1 = DeterministicState(s1, false); auto s2 = DeterministicState(s2, true); s0.addTransits(['0' : s1, '1' : s2]); s1.addTransits(['0' : s0, '1' : s2]); s2.addTransits(['0' : s2, '1' : s2]); auto dfa = DeterministicFiniteAutomaton( s0); auto trace = dfa.input(0001.dup); foreach (t; trace) { writeln(t.toString()); } writeln(Trace Length = ~ to!string(trace.length)); } Regards, Rob
Re: Code doesn't work - why?
This is actually a good question as this code isn't really complex or doesn't require the best possible performance. But in case I will ever need optimum performance I should have learned how to handle tasks with value types which is the main reason why I chose them instead of reference types - for learning purposes. - can't hurt! ;) Regards, Rob
Code doesn't work - why?
Hello, I came back to D after a longer break and just wanted to set up a small project to further get in contact with this language. However, it seems that the codes which simply shall simulate a deterministic finit automaton do not work correctly. CODE --- struct DeterministicState { public: this(string name, bool isFinal, DeterministicState[char] transits...) { this.name = name; this.finalState = isFinal; this.addTransits(transits); } this(string name, bool isFinal) { this.name = name; this.finalState = isFinal; } this(bool isFinal, DeterministicState[char] transits...) { this(, isFinal, transits); } this(DeterministicState[char] transits...) { this(, false, transits); } void addTransits(DeterministicState[char] newTransits) { foreach (immutable key; newTransits.keys) { transits[key] = newTransits[key]; } } string getName() const { return name; } bool isFinalState() const { return finalState; } bool hasNext(char input) const { return (input in transits) ? true : false; } DeterministicState getNext(char input) { return transits[input]; } string toString() const { return name; } private: string name; DeterministicState[char] transits; bool finalState; } struct DeterministicFiniteAutomaton { public: DeterministicState[] input(char[] input) { DeterministicState[] trace = [ start ]; auto currentState = trace[0]; foreach (immutable c; input) { if (currentState.hasNext(c) == false) { writeln(currentState.toString() ~ has next for ~ to!string(c)); break; } else { writeln(currentState.toString() ~ has NO next for ~ to!string(c)); } currentState = currentState.getNext(c); trace ~= currentState; } return trace; } this(DeterministicState start) { this.start = start; } private: DeterministicState start; } void main() { auto s0 = DeterministicState(s0, false); auto s1 = DeterministicState(s1, false); auto s2 = DeterministicState(s2, true); s0.addTransits(['0' : s1, '1' : s2]); s1.addTransits(['0' : s0, '1' : s2]); s2.addTransits(['0' : s2, '1' : s2]); auto dfa = DeterministicFiniteAutomaton(s0); auto trace = dfa.input(0001.dup); foreach (t; trace) { writeln(t.toString()); } writeln(Trace Length = ~ to!string(trace.length)); } --- The output is the following: s0 has NO next for 0 s1 has next for 0 s0 s1 Trace Length = 2 Which states that the trace for input 0001 has just a length of 2 instead of 4. And I do not really understand why s1 has no next item while it was defined in main. I hope someone can clear things up for me. I really don't get why this isn't working as intended. Regards, Rob
Re: Strange segfault (Derelict/OpenGL)
On Friday, 29 August 2014 at 15:20:00 UTC, Mike Parker wrote: As the README in Derelict 3 points out, that project is no longer updated. You should be using the binding from the DerelictOrg project [1] for anything new. [1] https://github.com/DerelictOrg/ stitch On 8/29/2014 9:16 PM, Robin Schroer wrote: On Friday, 29 August 2014 at 11:51:47 UTC, Marc Schütz wrote: display.Display.render() is what tries to render the triangle using a glBegin-block. Some code would be helpful. My first thought is that you aren't loading properly. DerelictGL3 does not load deprecated functions, but you're trying to call a deprecated function. Are you loading DerelictGL or DerelictGL3? So, I dug around a lot. I am using DerelictOrg, sorry if this was unclear, I was under the impression that it is still version 3. But anyway, I found out that some of my GL code is actually refering to null pointers because I have been using deprecated functions. So I am able to establish an OpenGL 3.3 context without crashing (although my test does not render yet, but that is another problem). Thank you to everyone nudging me in the right direction. -- Robin Schroer
Strange segfault (Derelict/OpenGL)
I'm not entirely sure where to post, so I will put it here. I'm playing around with D and Derelict 3 to make something with OpenGL (don't really know what yet). I managed to open a window, add an OpenGL context, clear the screen and flip buffers. But as soon as I try to render a triangle, my program crashes. I already tried hardcoding values in the shaders to rule them out. I end up with: Error executing command run: Program exited with code -11 Upon running with gdb, I get: Program received signal SIGSEGV, Segmentation fault. 0x in ?? () which is not really helpful to me. dub -v's output: [...] Full exception: object.Exception@source/dub/generators/build.d(405): Program exited with code -11 dub(pure @safe bool std.exception.enforce!(bool).enforce(bool, lazy const(char)[], immutable(char)[], ulong)+0x6b) [0x67346f] dub(void dub.generators.build.BuildGenerator.runTarget(dub.internal.vibecompat.inet.path.Path, const(dub.compilers.compiler.BuildSettings), immutable(char)[][])+0x4dc) [0x62db70] dub(void dub.generators.build.BuildGenerator.generateTargets(dub.generators.generator.GeneratorSettings, const(dub.generators.generator.ProjectGenerator.TargetInfo[immutable(char)[]]))+0x231) [0x62a75d] dub(void dub.generators.generator.ProjectGenerator.generate(dub.generators.generator.GeneratorSettings)+0x2de) [0x62f9a2] dub(void dub.dub.Dub.generateProject(immutable(char)[], dub.generators.generator.GeneratorSettings)+0xaa) [0x5f1f46] dub(int dub.commandline.GenerateCommand.execute(dub.dub.Dub, immutable(char)[][], immutable(char)[][])+0x677) [0x5e5b6b] dub(int dub.commandline.BuildCommand.execute(dub.dub.Dub, immutable(char)[][], immutable(char)[][])+0x8d) [0x5e5e81] dub(int dub.commandline.RunCommand.execute(dub.dub.Dub, immutable(char)[][], immutable(char)[][])+0x8d) [0x5e6041] dub(int dub.commandline.runDubCommandLine(immutable(char)[][])+0x1211) [0x5e3b8d] dub(_Dmain+0x20) [0x5e2334] dub(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll().void __lambda1()+0x18) [0x6ce504] dub(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x2a) [0x6ce45e] dub(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll()+0x30) [0x6ce4c4] dub(void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate())+0x2a) [0x6ce45e] dub(_d_run_main+0x1a3) [0x6ce3df] dub(main+0x25) [0x5e2979] /lib64/libc.so.6(__libc_start_main+0xf5) [0x3dcae21d65] I am using the current master versions of Derelict, dub 0.9.21, dmd v2.066.0, on Linux 3.15.7 x86_64 I can post my source if needed, but it is quite a lot already. I'm not really sure if it is my fault or a bug in Derelict or dmd, hopefully someone is able to track this down. -- Robin Schroer
Re: Strange segfault (Derelict/OpenGL)
On Friday, 29 August 2014 at 11:51:47 UTC, Marc Schütz wrote: On Friday, 29 August 2014 at 11:23:34 UTC, Robin Schroer wrote: Upon running with gdb, I get: Program received signal SIGSEGV, Segmentation fault. 0x in ?? () which is not really helpful to me. Can you still try to get a backtrace with `bt`? This looks like it's calling a null function pointer. I'm not familiar with Derelict, but I remember that some initialization needs to be done which involves setting up function pointers; your problem is probably related to that. Yes, I can: Program received signal SIGSEGV, Segmentation fault. 0x in ?? () (gdb) bt #0 0x in ?? () #1 0x004ad33e in display.Display.render() (this=0x77ecfe00) at source/dgame/display.d:95 #2 0x004a01d5 in D main (args=...) at source/app.d:41 #3 0x004cd9af in rt.dmain2._d_run_main() () #4 0x004cd902 in rt.dmain2._d_run_main() () #5 0x004cd968 in rt.dmain2._d_run_main() () #6 0x004cd902 in rt.dmain2._d_run_main() () #7 0x004cd883 in _d_run_main () #8 0x004acfb5 in main () display.Display.render() is what tries to render the triangle using a glBegin-block.
Re: Strange segfault (Derelict/OpenGL)
On Friday, 29 August 2014 at 12:41:38 UTC, ponce wrote: On Friday, 29 August 2014 at 11:23:34 UTC, Robin Schroer wrote: I'm not entirely sure where to post, so I will put it here. I'm playing around with D and Derelict 3 to make something with OpenGL (don't really know what yet). I managed to open a window, add an OpenGL context, clear the screen and flip buffers. But as soon as I try to render a triangle, my program crashes. As John Colvin said, forgetting to call DerelictGL3.reload() is a common error. I definitely reload after setting the context and before trying to render.
Re: How to return range constructs?
Hiho, @anonimous: Thank you for that hint with rdmd, I was already wondering what that was. @Mike Parker: Thank you very much for clearing that up for me. I really needed such a clear answer about this topic. So D language is highly advanced in meta programming and I should really begin to use it. =) Robin
Re: Template error on compiling ...
Hiho, thank you for your responses. This D language meta programming sounds funny and strange to someone who has never really worked with something like this but I understand its importance and will look more into working with it. =) Robin
How to return range constructs?
Hiho, for experimental and learning reasons I am working on a simple matrix library for D. And since ranges seem to be a cool feature of the D language I am currently trying to understand them and use them more in my codes. So I thought that it would be a nice feature if I could create methods to return specific ranges for certain matrix instances, e.g. something like getRowRange(size_t row) or getColumnRange(size_t col) which returns a range to easily iterate through a single row- or column vector of a matrix instance with a simple foreach loop. I store the matrix data within a single dimensional array for performance purposes instead of a jagged array: private { T[] data; Dimension dim; } The Dimension 'dim' is an object holding the number of rows and columns as well as some handy methods and properties such as isSquare etc. So my question is: How to define such a method which returns a range for a single row or column vector? The range should be modifiable depending on whether the matrix instance is const/immutable or not. Or isn't that possible at all? I thought that it could be tricky for row vectors since their data wouldn't be dense in memory. I've looked into the std.range documentation but doesn't seem to get a clue how to get this working. And if it works - what range type would fit best for my purposes - or do I need to create a sub-class of a certain range type specially fit for my matrix? My try so far: module neoLab.core.ColumnVectorRange; import std.range; import neoLab.core.Matrix; final class ColumnVectorRange(T) : RandomAccessFinite!T { private { T[] data; size_t cur = 0; size_t length = 0; } this(const ref Matrix m, size_t row) in { assert(row m.getDimension().rows, Row index is invalid.); } body { this.data = m.data; this.length = m.getDimension().cols; } ColumnVectorRange!T save() { // What does this do? } override T opIndex(size_t index) { return this.data[index]; // this correct? } override T moveAt(size_t index) { return this.data[this.cur]; // this good? } override size_t length() { return this.length; } override alias opDollar = this.length; // Is this nessecary? override ColumnVectorRange!E opSlice(size_t, size_t) { // What does this do in particular? } } I highly appreciate tips and answers! =) Thanks in advance. Robin
Re: How to return range constructs?
Hiho, ok thanks - I haven't known that interfaces are not a must extend like in java to serve as a real interface to something. This is strange to me in first place but has its pros. And when I want to build up a RandomAccessFinite I just have to implement the other methods as well, okay. :D Is this performance intense to iterate over these custom ranges instead of iterating plainly without them or is the compiler optimizing the overhead away? I have got another problem with my current implementation. My data field is private (as you can see from my first post) and I don't really want to create a public getter for it (because of the encapsulation) but I either don't want to copy it everytime I create a range for my matrix. On top of all I want to have seperate source files instead of one huge file (one module) where I can access everything (which is what I would need atm). So is there another way to solve this problem? Or do I really have to merge all my files into one big giantic file so that they are all in the same module? Robin
Template error on compiling ...
Hiho, I am currently working on a matrix library (matrices are templated structs) and have just implemented so-called ElementalOperations which perform certain tasks on mutable matrices. There is an abstract ElementalOperation where three different ElementalOperation types inherit from. These ElementalOperations are structured like that: module neoLab.core.ScaleRowOperation; import neoLab.core.ElementalOperation; import neoLab.core.Matrix; final class ScaleRowOperation(T = double) : ElementalOperation if (!hasIndirections!T) { private { size_t row = 0; T factor = 1; } this(size_t row, T factor) pure nothrow { this.row = row; this.factor = factor; } override void opCall(ref Matrix m) pure nothrow { foreach (immutable col; 0 .. m.getDimension().cols) { m[this.row, col] *= this.factor; } } override string toString() const pure nothrow { return Scale all elements of row ~ this.row ~ by factor ~ this.factor ~ .; } } So it is a fairly simple concept until now and I haven't spend time on improving its performance as I run into a strange compiler error, telling me the following: neoLab/core/ElementalOperation.d(6): Error: struct neoLab.core.Matrix.Matrix(T = double) if (!hasIndirections!T) is used as a type neoLab/core/SwapRowsOperation.d(18): Error: struct neoLab.core.Matrix.Matrix(T = double) if (!hasIndirections!T) is used as a type The matrix struct is defined as follows: struct Matrix(T = double) if (!hasIndirections!T) In the documentation hasIndirections!T reads: Returns true if and only if T's representation includes at least one of the following: - a raw pointer U*; - an array U[]; - a reference to a class type C. - an associative array. - a delegate. I don't know why this error occures at all. In my opinion it shouldn't, or am I doing something wrong again? Thanks in advance for help. =) Robin
Re: Template error on compiling ...
Hiho, both opCall(ref Matrix!() m) opCall(ref Matrix!T m) aswell as opCall(ref Matrix!(m)) or just opCall(ref Matrix m) give me all the same error as the one stated in the first post ... :/ Nothing really seems to work here. Robin
Re: Template error on compiling ...
Hiho, aww, that's a noob mistake of me. Thanks! Should take a closer look at the error messages next time a should think more about their special meaning ... It works now while it feels strange that I have to template the three classes as I am only working with references to matrix and in my understanding this shouldn't affect the compilate. But, well, in the end it works now.^^ Robin
Re: How to return range constructs?
Hiho, sorry for the double post but I can't find an edit button. I have managed to write a custom ForwardRange based on your code as I wished it to behave. However, the assertion fails on compilation, now. The only thing I have changed is that I have added a constructor as well as changing the type of T[] to Matrix!T pointer type. The general layout stayed the same and I don't think that a constructor may break the ForwardRange interface. Do you know what's wrong here? Here is the code: http://dpaste.dzfl.pl/8718b09cb825 Besides that ... are there nicer workarounds to prevent using matrix by value instead of storing it as a pointer which is kind of unsafe? Thanks in advance! Robin
Re: Template error on compiling ...
Hiho, just for you: the whole code! =) http://dpaste.dzfl.pl/cd1537571a4d The idea is that I have matrix instances and so-called ElementalOperations which are able to operate on matrices to solve certain algorithms object oriented without nasty loops and so on. This had worked perfectly in my java implementation so far. Robin
Re: How to return range constructs?
Hiho, I have made matrix a struct for a better performance and since everybody here on the forums was complaining about that it should be a struct type. When I uncomment the currently commented assertion I get linking errors. (these strange and nearly unreadable error messages.) Here is a part of them: ColumnVectorForwardRange.o: In function `_D6neoLab4core6Matrix13__T6MatrixTdZ6Matrix6__ctorMFNaNbNcxmxmxbZS6neoLab4core6Matrix13__T6MatrixTdZ6Matrix': neoLab/core/Matrix.d:(.text._D6neoLab4core6Matrix13__T6MatrixTdZ6Matrix6__ctorMFNaNbNcxmxmxbZS6neoLab4core6Matrix13__T6MatrixTdZ6Matrix+0x31): undefined reference to `_D6neoLab4core9Dimension9Dimension6__ctorMFNaNbNcxmxmZS6neoLab4core9Dimension9Dimension' ColumnVectorForwardRange.o: In function ... many many many lines of error messages ... ColumnVectorForwardRange.o: In function `_D6neoLab4core6Matrix13__T6MatrixTdZ6Matrix6randomFxmxmdddZS6neoLab4core6Matrix13__T6MatrixTdZ6Matrix': neoLab/core/Matrix.d:(.text._D6neoLab4core6Matrix13__T6MatrixTdZ6Matrix6randomFxmxmdddZS6neoLab4core6Matrix13__T6MatrixTdZ6Matrix+0x145): undefined reference to `_D6neoLab4core9Dimension9Dimension4sizeMxFNaNbNdZm' collect2: error: ld returned 1 exit status --- errorlevel 1 Robin
Re: Optimize my code =)
Hiho, as I used the ldmd wrapper for ldc2 I was able to use the same arguments given via the cmdfile. These were: -release -noboundscheck -O and -inline. Robin
Re: Optimize my code =)
Hiho, here are the results of both compilers (DMD and LDC2) on my system: LDC: = allocationTest ... Time required: 5 secs, 424 msecs multiplicationTest ... Time required: 1 secs, 744 msecs toStringTest ... Time required: 0 secs, 974 msecs transposeTest ... Time required: 0 secs, 998 msecs scalarMultiplicationTest ... Time required: 0 secs, 395 msecs matrixAddSubTest ... Time required: 0 secs, 794 msecs matrixEqualsTest ... Time required: 0 secs, 0 msecs identityMatrixTest ... Time required: 0 secs, 393 msecs = DMD: = allocationTest ... Time required: 3 secs, 161 msecs multiplicationTest ... Time required: 2 secs, 6 msecs toStringTest ... Time required: 1 secs, 365 msecs transposeTest ... Time required: 1 secs, 45 msecs scalarMultiplicationTest ... Time required: 0 secs, 405 msecs matrixAddSubTest ... Time required: 0 secs, 809 msecs matrixEqualsTest ... Time required: 0 secs, 430 msecs identityMatrixTest ... Time required: 0 secs, 350 msecs = All in all I must say that I am more pleased with the DMD results as I am kind of worried about the LDC allocation test performance ... I also had to rewrite parts of the codes as some functions just weren't pure or nothrow such as the whole things around this.data[] += other.data[]. Robin
Re: Optimize my code =)
, dualcore 2,2ghz, 4gb ram) There are still many ways to further improve the performance. For examply by using LDC on certain hardwares, paralellism and perhaps by implementing COW with no GC dependencies. And of course I may miss many other possible optimization features of D. I by myself can say that I have learn a lot and that's the most important thing above everything else for me here. Thank you all for this very interesting conversation! You - the community - are a part what makes D a great language. =) Robin
Re: Optimize my code =)
Hiho, I currently haven't got enough time to respond to all what have been said since my last post. However, here is the simple code: http://dpaste.dzfl.pl/3df8694eb47d Thanks in advance! I am really looking forward to your editing! =) Robin
Re: Optimize my code =)
Hiho, thank you for your code improvements and suggestions. I really like the foreach loop in D as well as the slight (but existing) performance boost over conventional for loops. =) Another success of the changes I have made is that I have achieved to further improve the matrix multiplication performance from 3.6 seconds for two 1000x1000 matrices to 1.9 seconds which is already very close to java and c++ with about 1.3 - 1.5 seconds. The key to victory was pointer arithmetics as I notices that I have used them in the C++ implementation, too. xD The toString implementation has improved its performance slightly due to the changes you have mentioned above: 1.37 secs - 1.29 secs I have also adjusted all operator overloadings to the new style - I just haven't known about that new style until then - thanks! I will just post the whole code again so that you can see what I have changed. Keep in mind that I am still using DMD as compiler and thus performance may still raise once I use another compiler! All in all I am very happy with the code analysis and its improvements! However, there were some strange things of which I am very confused ... void allocationTest() { writeln(allocationTest ...); sw.start(); auto m1 = Matrix!double(1, 1); { auto m2 = Matrix!double(1, 1); } { auto m2 = Matrix!double(1, 1); } { auto m2 = Matrix!double(1, 1); } //{ auto m2 = Matrix!double(1, 1); } sw.stop(); printBenchmarks(); } This is the most confusing code snippet. I have just changed the whole allocation for all m1 and m2 from new Matrix!double (on heap) to Matrix!double (on stack) and the performance dropped significantly - the benchmarked timed raised from 2,3 seconds to over 25 seconds!! Now look at the code above. When I leave it as it is now, the code requires about 2,9 seconds runtime, however, when enabeling the currently out-commented line the code takes 14 to 25 seconds longer! mind blown ... 0.o This is extremely confusion as I allocate these matrices on the stack and since I have allocated them within their own scoped-block they should instantly release their memory again so that no memory consumption takes place for more than 2 matrices at the same time. This just wasn't the fact as far as I have tested it. Another strange things was that the new opEquals implementation: bool opEquals(const ref Matrix other) const pure nothrow { if (this.dim != other.dim) { return false; } foreach (immutable i; 0 .. this.dim.size) { if (this.data[i] != other.data[i]) return false; } return true; } is actually about 20% faster than the one you have suggested. With the single line of return (this.dim == other.dim this.data[] == other.data[]). The last thing I haven't quite understood is that I tried to replace auto t = Matrix(other).transposeAssign(); in the matrix multiplication algorithm with its shorter and clearer form auto t = other.transpose(); // sorry for the nasty '()', but I like them! :/ This however gave me wonderful segmentation faults on runtime while using the matrix multiplication ... And here is the complete and improved code: http://dpaste.dzfl.pl/7f8610efa82b Thanks in advance for helping me! =) Robin
Re: Optimize my code =)
Hiho, thanks again for your answers! I don't know where to start ... @Stanislav Blinov: I am not currently aware of the move semantics in D or what it is called there. However, I am not quite sure if D does an equally good job as C++ in determining if a value can be moved or not. I have made some simple tests which showed me that the swap-assignment and the move-constructor are never called in D at code where C++ would certainly take them, instead D just copies values which were in fact rvalues ... (Maybe I just don't get the whole thing behind the scenes - and I am really hoping it.) My statement that the in and body block of the assignment operator slows down the whole code isn't true anymore. Don't know what fixed it tough. @bearophile: Yeah, you are completely right - I am super confused at the moment. I always thought that D would be much easier to learn than C++ as all the people always say that C++ is the most complex language. After what I have learned so far D seems to be much more complex which isn't bad in general, but the learning curve doesn't feel so well atm as I am mainly confused by many things instead of getting what happens behind the scene. (e.g. move semantics, the whole army of modifiers, immutability which result in zero performance boost in non-paralell environments, the fact that classes are by-ref and structs are by-val is also confusing from time to time to be honest.) When I started to write the C++ matrix library after I have written the Java matrix library to get to know what both languages can achive I have also had to start learning C++ as well. I bought a book and after 2-3 weeks I got the concepts and everything went as excepted and no things seemed to be hidden behind the scenes from me, the programmer which was in fact a nice experience when trying to optimize the code until it was equally fast as the java code or even faster. D seems to be more problematic when it comes to learning how to optimize the code. To summarize, I am still a beginner and learn this language as it has got cool, new and advanced features, it has not so many legacy issues (like C++), it unites object orientated, functional as well as imperative and paralell programming paradigms (still amazed by that fact!), runs native and isn't bound to any operating system or a huge runtime environment (java/c#). That's why I am learning D! =) I would love to see how much performance a D vetaran like you is able to grab out of my codes. Just tell me where I shall upload them and I will do so. Don't expect too much as I am still a beginner and as this project has just started. I didn't want to implement the whole functionality before I know how to do it with a good result. ;-) The matrix multiplication you have posted has some cool features in it. I especially like the pure one with all that functional stuff. :D @Nick Sabalausky: Don't be shocked at the bad performance of a beginner D programmer. At least I am not shocked yet that my D implementation isn't performing as well as the highly optimized C++11 implementation or the JIT-optimized Java implementation. In general one can not compare the results of a native compilation optimization which shall run on different hardwares and a JIT optimization which is able to pull out every single optimization routine because it knows the system and all its components to compile at. There is also the LDC2 and the GDC which should also improve the general performance quite a bit. However, what is true is, that it is (at least for me) harder to learn how to write efficient code for D than it was to learn it for C++. And keep in mind that my Java implementation (which runs nearly as fast as the C++ implementation) is written just to fit for performance. I have had to do dirty things (against the general Java mentality) in order to achive this performance. Besides that I couldn't implement a generic solution in Java which wasn't five to ten times slower than without generics as generics in Java are a runtime feature. So all in all Java is only good in performance if you don't use it as Java (purely object oriented etc.) ... but it works! :D @All of you: What I have done since the last time: I have changed my mind - matrix is now a value type. However, I wasn't sure about this step because I planned to implement dense and sparse matrices which could inherit from a basic matrix implementation in thus required to be classes. I have also removed that nasty final struct statement.^^ However, benchmarks stayed the same since the last post. Hopefully I haven't forgotten to say anything important ... Robin
Re: Optimize my code =)
Hiho, wow, first of all: this community is awesome - so many kind and interesting answers. =) With your help I was able to achieve a performance boost for several different operations. Some benchmarks: Allocation of 5 10.000 x 10.000 matrices in a row: Before: ~8,2 seconds After: ~2,3 seconds (with the minimallyInitializedArray!) Multiplication of two 1000x1000 matrices: Before: ~14,8 seconds After: ~4,3 seconds However, I think there is still much potential in order to further optimize this code. Let me tell you what changes I have mainly performed on the code so far ... Matrix is still a class but I changed it to a final class preventing matrix methods to be virtual. Dimension is now a final struct (don't know if 'final' is affecting structs in any way tough ...). This mainly gave the multiplication a huge performance boost. When converting the Matrix to a struct from class the multiplication even lowered from ~4.3 seconds to about 3.6 seconds. However, I am currently not sure if I want matrices to be structs (value types). Besides that I tried to add nothrow and pure as attribute to every possible method. However, as it turned out I wasn't able to add the pure modifier to any method as I always called an impure method with it (as stated by the compiler). This actually made sense most of the times and I think the only pure methods now are the constructor methods of the Dimension struct. What may still speed up things? In my tests it turned out that the simple code: auto m1 = Matrix!double.random(1000, 1000, -10, 10, 0.25); auto m2 = Matrix!double.random(1000, 1000, -10, 10, 0.25); auto m3 = m1 * m2; Called the normal copy-constructor. This is sad as it would be a huge performance boost if it would make use of the move semantics. (In the C++ matrix codes this scenario would actually call move assignment operator for matrix m3 which is much much faster than copying.) But I haven't figured out yet how to use move semantics in D with class objects. Or is that just possible with struct value types? I have also tried the LDC compiler. However, it gave me some strange bugs. E.g. it didn't like the following line: ref Matrix transpose() const { return new Matrix(this).transposeAssign(); } And it forced me to change it to: ref Matrix transpose() const { auto m = new Matrix(this); m.transposeAssign(); return m; } Which is kind of ugly ... I hope that this is getting fixed soon, as I imply it as correct D code because the DMD is capable to compile this correctly. Some of you came up with the thing that transposing the matrix before multiplication of both takes place must be much slower than without the transposition. In my former Java and C++ programs I have already tested what strategy is faster and it turned out that cache efficiency DOES matter of course. There are also papers explaining why a transpose matrix multiplication may be faster than without transposing. In the end this is just a test suite and there is already an even faster approach of a matrix multiplication which runs in O(n^2.8) instead of O(n^3) as my current simple solution. And with the power of OpenCL (or similar) one could even lift a matrix multiplication to the GPU and boom.^^ But the current task is to find general optimized code for the D language - this thread already helped me much! I wasn't aware that D is actually capable of lazy evaluations other than the if-pseude-lazy-evaluation which is kind of cool. However, I still have to look that up in order to maybe find a use for it in these codes. SIMD instructions also sound extremely cool but a little bit too complex regarding the fact that I am fairly new to D and still learning basics of this language. In the end I wanted to state something which I found very iritating. Bearophile stated correctly that my pre-conditions for the index operators are all wrong and corrected my code with some smooth additions: T opIndex(in size_t row, in size_t col) const nothrow in { assert(row nRows); assert(col nCols); } body { return data[dim.offset(row, col)]; } The in and body statements are cool as far as I realize what they are for. However, in the benchmarks they had a clear and noticable negative impact on the matrix multiplication which raised to ~8 seconds from ~4 seconds with his code compared to mine. When leaving out the in and body statement block and using only one normal block as follows, it stayed at the 4 seconds duration for that task and so I think that the compiler won't optimize things in an 'in' code block - is that right? T opIndex(in size_t row, in size_t col) const nothrow { assert(row nRows); assert(col nCols); return data[dim.offset(row, col)]; } Thanks again for all your helpful comments and thanks in advance - I am eagerly looking forward for your future comments! =) Robin
Optimize my code =)
() method which creates a matrix with random values. There it is unnecessary that the (sometimes huge) array is completely initialized with the type's init value. Thanks in advance! Robin