BrowserUk has asked for the wisdom of the Perl Monks concerning the following question:
Purely recreational: Produce a lazy Same Fringe() implementation in Perl 5?
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Challenge: Perl 5: lazy sameFinge()?
by roboticus (Chancellor) on Jun 29, 2013 at 19:05 UTC | |
I didn't get anywhere on your binary string analysis problem yesterday. I was working on a couple different things, but none of 'em led me anywhere good. Anyway, for the fringe thing:
Update: I've posted a version (with the better iterator mentioned further down in this thread) to Rosetta Code. I couldn't find my original account information (or perhaps I misremembered and didn't create an account there. I didn't want to clutter up the thread with yet another version. I've also made that one meet the spec (i.e., early termination). ...roboticus When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] |
by LanX (Saint) on Jun 29, 2013 at 20:11 UTC | |
You are using many copies to flatten the stack. with some dumps of intermediate @stack-states: Read more... (1213 Bytes)
out
Cheers Rolf ( addicted to the Perl Programming Language) | [reply] [d/l] [select] |
by roboticus (Chancellor) on Jun 29, 2013 at 20:59 UTC | |
| [reply] | |
by roboticus (Chancellor) on Jul 02, 2013 at 15:03 UTC | |
LanX: On rereading this thread, I think you may misunderstand what my code is doing. When you said that my code wasn't "lazy", I thought you meant that it was working too hard, but in retrospect I think you're meaning that I'm flattening the entire tree at once before returning anything. But I'm not doing that--Instead, I'm properly visiting the tree, traversing the left subtree(s) until I find the first (leftmost) leaf. The unused right subtrees are left on the stack for processing later. Since my test data was small and the tree left-heavy, though, it's hard to see that. Below (in readmore tags for those uninterested) is a run of the original iterator that you instrumented with a more "interesting" tree. I also have the output of my better version (also instrumented): Read more... (6 kB)
...roboticus When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] [select] |
by LanX (Saint) on Jul 02, 2013 at 17:15 UTC | |
by Laurent_R (Canon) on Jun 29, 2013 at 21:43 UTC | |
Beautiful. I made a first try to traverse the tree recursively and then figured out that it does not work for comparing two trees, it seems impossible (or at least very complicated) to recurse on two data structures simultaneously. So, I figured out that I probably needed an iterator (well actually two iterator functions) to return the leaves on demand, leading to a solution quite similar (at least in spirit) to yours, but, since I have done that only once or twice before, and quite some time ago, I had to go back to Mark-Jason Dominus' Higher Order Perl book to figure out how to do that. My iterators now seem to work more or less properly (although they are somewhat clumsy compared to yours), so that I am almost there (the main loop is not very complicated), but you did it before (and better). Your code definitely looks much better than what I have so far, so that, unless I come with a brilliant new idea (unlikely), I will not submit mine; Congratulations, roboticus. Beautiful work. To LanX: using iterators is what is needed to make the process lazy (there may be other solutions, but this is a good one), or to make it possible to have it lazy. roboticus did not really make it completely lazy (the program is counting the number of differences, rather than exiting at the first difference), but it only takes a minor change to make it truly lazy (if we have the same understanding of lazyness). BTW, roboticus, it would be good to publish your solution on the Rosetta Stone site: when you see solutions in some languages taking 200 lines of code or more, and a solution like yours taking more than 10 times less code, you get a certain picture of the amount of effort to get something done in various languages. ADA or Java, just to name two, are very powerful languages, no doubt, but need a lot of efforts to do something simple. In contrast, languages like Perl, Python, Haskell or Lisp (just a few examples) have much more expressive power. And, even thougn IT managers usually don't really understand the difference, they do if you tell them: "well this I can do in two weeks with XYZ super-duper object language , and in 2 days in Perl or Haskel (or Lisp, or whatever). | [reply] |
by roboticus (Chancellor) on Jun 30, 2013 at 00:27 UTC | |
Don't worry about it, post your solution--One of the fun things about programming is seeing how other people do things, and then learning their techniques! Not only that someone might offer a suggestion to you that could lead in a different and better direction. As LanX mentioned, mine's computationally expensive. That's not a real problem in this case. But if someone needed to compute as many fringes per second as possible, then a faster solution would be helpful. I can't help but feel that there's an even nicer way to do it, but I haven't thought of it yet. Also, the code above wasn't my first shot at it. It was an interesting problem, so I spent a bit of time on it. I went through six iterations to get it as simple as it is now. Once I had some functional code, I thought that there was just too much special-case handling code. So I tried to rearrange things to remove the special cases. It's pretty simple in the final version, but I didn't see the simple version at first--I seem to have a habit of seeing the trees before noticing the forest. It took me six iterations to get to the version I posted. My first version was this:
(This is before I wrapped up the stack in a closure to make the iterator useful.) As you can see, there are just too many special cases in there. Each time I removed one special case, it gave me an idea for the next one. I'm pretty happy with the version I ultimately wound up with, even though I suspect that it could be better yet. It would be pretty nice if I could think up a nice simple way to do it and reduce the array rebuilds, too. I tried to switch back to the push/pop, as I think that would be more efficient, but most of the special cases were due to my use of push/pop at the start. Switching to shift/unshift allowed me to remove one or two odd bits. I think I have a rosetta code login at work, so I'll try to remember to post it there on Monday. And, even though IT managers usually don't really understand the difference, they do if you tell them: "well this I can do in two weeks with XYZ super-duper object language , and in 2 days in Perl or Haskel (or Lisp, or whatever). I wish the people at $work were susceptible to that argument. I used this very argument at work the other day. They needed a file generated, so I quoted a day in Perl or a week in .Net or PL/SQL. Also, I mentioned that due to time pressures on the current project, I could just squeeze the Perl version into my schedule. There's little Perl expertise at $work, and they're fearful enough of it, that they opted to do it in PL/SQL. 10 days later and it works. Luckily, due to the time pressures, *I* didn't have to do the task. But I'm frequently surprised when it's "rush rush rush!" but when you want to do it with a tool they're uncomfortable with, saving all the time in the world wouldn't be enough for them. ...sigh... ...roboticus When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] |
by Laurent_R (Canon) on Jun 30, 2013 at 14:58 UTC | |
by LanX (Saint) on Jun 30, 2013 at 16:30 UTC | |
by roboticus (Chancellor) on Jun 30, 2013 at 14:43 UTC | |
As I mentioned yesterday, seeing what other people do can give you inspiration. Case in point: I just reviewed the solution hdb posted, and got the hint I needed to make mine better: Rather than using just a stack, hdb uses a stack and a reference to the current (sub)tree being worked on. By using the same I idea, I was able to come up with a new version of get_tree_iterator that I like even better:
This version still descends down the left tree until it hits a leaf, but it uses much less manipulation of the @stack array, and uses the right hand side of the array, which is (I expect) more efficient than the left side. (Editing the right side of the array may cause an expansion of the array, but I'm thinking that expanding the left side of the array may cause unnecessary array copies.) When I look at this version, I don't feel like I'm missing anything. (Not to say that I'm not--It's amazing how often one can make significant improvements to "optimized" code.) ...roboticus When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] [select] |
|
Re: Challenge: Perl 5: lazy sameFringe()?
by hdb (Monsignor) on Jun 30, 2013 at 10:31 UTC | |
Very nice exercise!
| [reply] [d/l] |
by LanX (Saint) on Jun 30, 2013 at 11:49 UTC | |
updateoops!!! I just realized that the task is restricted to binary trees! =) (how boring ;) Cheers Rolf ( addicted to the Perl Programming Language) | [reply] [d/l] |
by BrowserUk (Patriarch) on Jun 30, 2013 at 12:35 UTC | |
Nice++ A solution that actually matches the spec :) With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
Re: Challenge: Perl 5: lazy sameFringe()?
by LanX (Saint) on Jun 30, 2013 at 00:00 UTC | |
NOTE that this example iterates over HoH not AoAs (which is a bit silly b/c order matters) since I have only 5.10 installed. With >=5.12 each should also work with ARRAYs! (testing appreciated) It might not be the most elegant solution but a) it's really lazy - not only for the programmer - and b) it can iterate nested Arrays and Hashes alike for >=5.12. c) it's quite fast. d) I can tell the recursion "depth" of each iteration. NOTE I'm only returning 3 values for better visualization/debugging. Only $v matters for this task.
out
a more functional solution on Monday.
Cheers Rolf ( addicted to the Perl Programming Language)
UPDATEI just realized that it's about binary trees and that the representation of them is free. So when choosing nested hashes with keys L and R , this algorithm already delivers the needed features. =)
UPDATELimitations see Re^3: Challenge: Perl 5: lazy sameFringe()? | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Jul 01, 2013 at 05:36 UTC | |
UPDATE I just realized that it's about binary trees and that the representation of them is free. So when choosing nested hashes with keys L and R , this algorithm already delivers the needed features. Have you tested your routines using the same test data as used by the rosetta challenge? If not, you haven't even begun to enter into the spirit of the challenge. Which makes all your posts in this thread challenging the efficacy of other peoples attempts are at best misplaced noise; and at worst, mind-blowing arrogance and misunderstanding,. With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
by LanX (Saint) on Jul 01, 2013 at 10:15 UTC | |
yes and it fails (only) when comparing identical hashes. This resulted into this thread , which I suppose you are well aware of. (Demonstrating the limitations of each is the most valuable outcome for me.) None of the solutions so far can compete with the elegance of the idiomatic P6's gather/take resp. Py's yield which is a bit frustrating ... Having specialized solutions which only work for binary AoAs is no big compensation...
Cheers Rolf ( addicted to the Perl Programming Language) | [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Jul 01, 2013 at 10:57 UTC | |
by LanX (Saint) on Jul 01, 2013 at 23:38 UTC | |
|
Re: Challenge: Perl 5: lazy sameFringe()?
by BrowserUk (Patriarch) on Jun 30, 2013 at 06:43 UTC | |
My attempt (not keen on the redo loop):
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
Re: Challenge: Perl 5: lazy sameFringe()?
by Laurent_R (Canon) on Jun 30, 2013 at 15:10 UTC | |
This is my solution. As I said above, I think it is less elegant than others published above, but I follow Roboticus's recommendation to publish it nonetheless.
Results comparing tree1 and tree3:
And comparing tree1 and tree2:
| [reply] [d/l] [select] |
by Laurent_R (Canon) on Jul 01, 2013 at 09:41 UTC | |
OK, BrowserUK, here we go with a sameFringe function and the test data copied from your posted solution. Note that I had to make a small change in my closure (unshift instead of push on the @ref_list array), because my original code did not compare $a and $c correctly (the leaves were appearing in opposite order).
The following is the output:
| [reply] [d/l] [select] |
by BrowserUk (Patriarch) on Jul 01, 2013 at 05:22 UTC | |
Laurent_R++ Another solution that works and (almost) meets the specs. It would be easier to compare with other attempts if you wrapped your algorithm up in a sameFringe() subroutine -- same args and return -- as is used in the linked article. It is also a good idea to test using the same tests as they use. They have been quite carefully designed (or arrived at) to test several particular edge cases. With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
Re: Challenge: Perl 5: lazy sameFinge()?
by LanX (Saint) on Jun 29, 2013 at 16:27 UTC | |
I just feel too lazy now... ;-)
SCNR Rolf ( addicted to the Perl Programming Language) PS: Monday perhaps... BTW nice use case for P6's Gather/Take | [reply] |
|
Re: Challenge: Perl 5: lazy sameFringe()?
by hdb (Monsignor) on Jun 30, 2013 at 13:16 UTC | |
Laurent_R above is looking for a recursive solution. Recursion is the easiest way to traverse a tree. My idea to do this is sketched like this for simultaneous recursive traversal:
As I have no experience with threads, I do not really know how to start this or whether it is even feasible. What do you think? LanX: As far as I can see, this would work for trees with more branches than two... | [reply] [d/l] |
by BrowserUk (Patriarch) on Jun 30, 2013 at 13:54 UTC | |
That looks more like a fork-based approach than a thread based. See mine for a recursion and threads approach. I'd love to see a Coro solution here. With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
|
Re: Challenge: Perl 5: lazy sameFringe()? (threads::Gather Configurably truely lazy or semi-lazy)
by BrowserUk (Patriarch) on Jul 02, 2013 at 20:24 UTC | |
A better implementation I think:
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |