Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chris c2 #2

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Chris c2 #2

wants to merge 5 commits into from

Conversation

ceebo
Copy link
Contributor

@ceebo ceebo commented Dec 16, 2014

Here are a few more patches. I used std::stringstream and std::string for GetRLE. Memory management is much easier and g++ gives a load of warning about plain char * otherwise. Evolve(after, before, iters) is something I would like to go in. It seems to suit my way of working better. What do you think?

Also I have some ideas for more changes:

First, Rename the three comparison functions as follows so that everything is the same between functions for GlobalState and the rest:

a) Get rid of Contains(main, spark) and AreDisjoint(main, spark) and rename AllOn(main, subset) and AllOff(main, subset) like in the Global case.

b) Rename AreEqual to IsEqual in both cases. I think that the global version AreEqual(pat) with one argument sounds bad so better to rename both. IsEqual(pat1, pat2) sounds ok I think.

Second, I think it could be a good idea to move to separate LifeAPI.h and LifeAPI.cpp. I think it would be a very attractive feature for users if LifeAPI.h was a super clean and super concise file that explains 90% of the functionality of LifeAPI without even needing to read the documentaion.

Thoughts?

(in particular (x & 1 == 0) <> (x % 2 == 0) due to C precedence rules)
And use LifeState *state consistently

Also make the two operand Parse function the base implementation.

Four operand Parse is now derived from it.
PRNG courtesy of Stebastian Vigna at http://xorshift.di.unimi.it
Previously no $ was printed if line ends in a live cell.

Easy fix was to take numempty++ out of the "else" block but
I rewrote as well.

Also, GetCell should not have "val" as argument
@simsim314
Copy link
Owner

I used std::stringstream and std::string for GetRLE.

I've some issue with namespace std (it requires some lib/dll). I wanted to avoid std, also because it's known source of performance troubles (if you add benchmark - see how adding "using namespace std" will effect you, it's simply horrible). I know you used it correctly, just saying I want to keep it simple and out of troubles.

Evolve(after, before, iters) is something I would like to go in.

This is only another overload - so great.

*a) - doesn't influence anything external.

*b) - rename AreEqual to IsEqual - hmm ok. I think IsEqual is the standard, but I saw AreEqual few times. Anyway IsEqual is fine by me.

I think it could be a good idea to move to separate LifeAPI.h and LifeAPI.cpp.

  • I don't like the idea too much. This will require linker, and MAKE etc. adds complexity, and another source of troubles. I do see the appeal of .h and .cpp, I'll look later what are the consequences regarding building projects.
  • There is also obvious way to convert many structs to classes. Which I also wanted to avoid, only to maintain single #include, this really simplify things at build/linking stage. I really don't like to get linker errors, and at the point you start to divide your project into pieces like that, you start to get LNKs.
  • I do think that few includes instead of just LifeAPI.h alone is probably necessary.
  • Have some #def and #ifdef for LifeAPI.
  • Documentation is required anyway. I do agree LifeAPI.h is a mess though, and I understand there is a reason for .h .cpp convention. Let me see if it's possible to maintain simplicity and have more "hierarchy".

@simsim314
Copy link
Owner

Thinking about it a little bit.

We can have nice separation into .h and .cpp for coding. I'll write simple script that unifies all files together into one single .h file, to use #include LifeAPI.h alone, for external usage. What do you think?

I think this can allow adding classes. If so LifeState could be converted to class. Let me see how complex this change is.

@ceebo
Copy link
Contributor Author

ceebo commented Dec 17, 2014

I wanted to avoid std

Ok, your choice. Actually I never head that std was difficult to find lib/dll for. Anyway, isn't the current GetRLE using O(n^2) memory? Lots of malloc's but no free's. Also it gives this warning a lot in g++: deprecated conversion from string constant to ‘char’*

If we go to separate .cpp and .h only <string> will need to be included in the LifeAPI.h. <sstream> can stay in the cpp. Also you could use std::vector as the implementation for ResultManager:

Just typedef std::vector<LifeState> ResultManager and you are nearly done.

Another argument for separate .h and .cpp is that currently lots of stuff that should not be seen by the end user is leaking out, e.g. GlobalState, Temp, Temp1, Temp2, CirculateLeft, .... I'm sure there is more.

@simsim314
Copy link
Owner

I still want to give the end user only single "LifeAPI.h" with lots of code - including many classes inside single .h file. My idea is to "combine" LifeAPI.h from few smaller classes and methods, to make the development more systematic. As developers we can setup the compiler to compile .cpp hierarchically. But as the end user, I just want to add LifeAPI.h and have it all (maybe later we will have some additional includes, but for now I want to keep the usage of LifeAPI as simple as it gets).

The compile time is pretty small, so the main reason for separating .h and .cpp (to allow modular development, and reduce compilation time) is not present in this project.

As for allowing access to private members - I've started with c approach, without private - public option at all. If we will move into classes, we can hide stuff as privates, inside LifeAPI.h itself.

@ceebo
Copy link
Contributor Author

ceebo commented Dec 17, 2014

Ok, your choice. But I don't think it's a great burden on the user to type

g++ my_prog.cpp LifeAPI.cpp -o my_prog

instead of

g++ my_prog.cpp -o my_prog

In windows it can't be much harder.

PS. I just thought of this bit-hack style method for implementing BitIterator. x[64] should iterate through all subsets of mask[64].

for (i = 0; i < 64; i++)
        {
                x[i] = ((x[i] | ~mask[i]) + 1) & mask[i];
                if (x[i])
                        break;
        }

@simsim314
Copy link
Owner

Well think of computer science student. He wants to use #include < stdio.h > and to have printf and scanf functions immediately. No one wants to go into compiler flags and start tweaking them around after #include. I know it looks simple after you know it (and that stdio.h is actually using lib), but many times you just want to #include and forget.

There are solution to this of course - like releasing .lib files together with .h etc. still I prefer to keep it as simple as #include<stdio.h> if possible.

As I mentioned - let's have normal c++ project, I'll also post all compiler flags for it. But just have in mind that our "release" for the "clients", will consist from single LifeAPI.h - it's really not an issue to convert normal project into single .h, and as far as I understand it's exactly the same thing, it's just that the compilation time takes a bit longer.

EDIT: There is another advantage of adding only .h file. One can tweak it around as he wishes. If someone finds a bug he could fix it in LifeAPI.h itself, without the need to download the project, and make it compile.

EDIT2: I want to make some smarter BitIterator, that will work in amortized O(1) + will run in cols like lifesrc, and if some col failed it will continue from the place it failed without iterating further. But we can start from your piece of code - it's a good start.

@ceebo
Copy link
Contributor Author

ceebo commented Dec 17, 2014

With a single .h file it seems impossible to shield the global variables GlobalState, Temp etc from the end user. Ok, you can put them in a class, but then that class still needs to be globally visible. That seems like an uglier situation than having separate LifeAPI.cpp and LifeAPI.h to me.

Regarding the global Temp variables, they can be got rid of by putting Temp on the stack of the function. LifeState is fixed size so there should be no cost for doing this.

I never looked at the lifesrc program. It sounds interesting.

@simsim314
Copy link
Owner

lifesrc is more know as WinLifeSearch (which is simply lifesrc with GUI). You have N columns with 3 states, life-dead-unknown. It has special rule that replace unknown to what would you get in life (like 4 neighbors + any unknowns will be dead, or 2 life + unknown will remain as is). Then the program iterates the unknown states, to try to figure out what can be flipped from unknown to known. It searches for oscillators and spaceships. You can also search for parents with it - it's the best way to find sparks that later become the pattern you need. This is how codeholic found the spark for the dart.

This approach reduces a lot of brute force checking, as sometimes every unknown state will yield no results.

But because it has three states it's sometimes slower than simple brute force, and as deeper you search the more unknowns you'll get, so the less efficient it becomes. This is why 8 generation is kinda the limit for this approach. Using LifeAPI "smart brute force" iterator that works fast and doesn't continue after contradiction has been found, might break this barrier (especially if we will have GPU accelerator). Using brute force and fast bit iterator, will allow iterate much deeper, because brute force doesn't care how deep you search the pattern, place 30 unknown bits - and iterate as much as you like. This would be great for smart parent search as well.

If you want to practice BitIterators, just make a BitIterator that finds some of the small p2 spaceships. You can start from iterating on two columns of 10x2 and see what can move one cell after 2 generations. Then add another column to find another non-contradiction etc. do it iteratevlly, until you'll find p2 spaceship.


As for .cpp and .h topic - The only useful way I see on how to release LifeAPI without headache, is to add LifeAPI.lib with LifeAPI.h - I don't like this idea for simple reason. Think that I have borland c++ compiler (or some other strange creature and strange OS), and it gives me 10 errors. With LifeAPI.h I can go and fix it pretty simply. With some pre- compiled library, or flags in compiler that will give me linker errors, or maybe my compiler has some other issues, or maybe I use some "smart" tool that configs the compiler flags, and this is not too friendly tool - It's just much harder. Keeping with the current simplicity, will allow people to enjoy LifeAPI without thinking too much about anything. If some "smart guy" wants to use Temp, or something of this sort, he's welcome to destroy his app as much as he wished. I just hope that people who want to write fast and simple apps would be able to do so. We can also give some "ugly" names to objects that we don't want the end users to use, to warn them.

I don't like c++ too much, because it's sometimes VERY hard to find what is wrong, while something stupid using std can kill your performance. So I want to keep it simple for the "end-user" which we should assume is not "stupid" as he writes c++ app, but also let's keep our requirements of him to the bare minimum. Some more advanced users can always peek into the more "systematic" part of the project, with classes hierarchically divided. LifeAPI.h will be the "plug and play" version of the project.

@ceebo
Copy link
Contributor Author

ceebo commented Dec 17, 2014

Ok, it's just a difference of opinion. As an end user I would find it not so simple that LifeAPI.h is introducing a lot of variables and functions that I don't need. I am lazy and would prefer to see just 20-30 lines of clean function declarations in LifeAPI.h and all the implementation in LifeAPI.cpp.

But never mind, we can't keep talking about this forever :)

@simsim314
Copy link
Owner

We do agree about the best way to maintain the project, the question is how to release it to the "clients". So the release which happens once in a while anyway, can have two options:

  1. "Plug & Play" with a lot of mess, but straight forward usage.
  2. Add LifeAPI.o to the linker, and have much cleaner "Plug & Play".

We will give the users advice to first try the Plug & Play to see what LifeAPI is all about. You just #include LifeAPI.h and play around with it. If you like the concept, you can "install" much cleaner version of LifeAPI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants