Ah... ignore my noise here - Brian Schott pointed out my problem off list. (I had a 16 where I should have had a 15 and I was not paying attention to the error - it was not an error from the assert but an error from the definition, which means the definition I was running was a different one.)
I'll fix this up, but for now.. just ignore my earlier post here. Thanks, -- Raul On Sat, Jan 6, 2018 at 12:40 AM, Raul Miller <[email protected]> wrote: > Hmm... > > It seems to me that this kind of problem could use a sequential > machine (dyadic ;:) implementation to do some of the heavy lifting. > > Sadly, I believe i have run into a J engine bug, which prevents me > from completing this idea. > > I'll drop my broken code here to show what I mean: > > m345=:(5;(0 10#:10*T=:".;._2]0 :0))&;: > 0.1 2.1 > 1.0 1.0 > 1.0 3.0 > 1.0 4.0 > 5.0 1.0 > 5.0 6.0 > 1.0 7.0 > 1.0 8.0 > 1.0 9.0 > 10.0 1.0 > 10.0 11.0 > 1.0 12.0 > 1.0 13.0 > 1.0 14.0 > 1.0 15.0 > 16.0 1.0 > ) > > assert 1-:m345 0 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 > assert 0-:m345 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 > > My original idea was to use function code 13 and then use (,15)-: ... > as the implementation. That doesn't work, though. So I was looking at > a trace of the execution (the function code 5 thing that's currently > there, and ... well, look at this: > > (,.((-<.T){~2{"1 m345),.m345) 0 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 > 0 0 _2 0 _1 0 0 0 1 > 1 0 _2 1 0 0 1 2 1 > 1 _1 _3 2 1 2 1 3 0 > 1 _1 _4 3 1 3 1 4 0 > 0 _5 _1 4 1 4 0 5 0 > 0 _5 _6 5 1 5 0 5 0 > 0 _5 _6 6 1 5 0 5 0 > 1 _5 _6 7 1 5 1 6 0 > 1 _1 _7 8 1 6 1 7 0 > 1 _1 _8 9 1 7 1 8 0 > 1 _1 _9 10 1 8 1 1 0 > 0 _1 _1 11 1 1 0 1 0 > 1 _1 _1 12 1 1 1 1 0 > 1 _1 _1 13 1 1 1 1 0 > 1 _1 _1 14 1 1 1 1 0 > 1 _1 _1 15 1 1 1 1 0 > 1 _1 _1 16 1 1 1 1 0 > 0 _1 _1 17 1 1 0 1 0 > 0 _1 _1 18 1 1 0 1 0 > 0 _1 _1 19 1 1 0 1 0 > > The columns here are (left to right), the input bit, two columns for > the relevant row from my machine definition (I am just interested in > the next state from T, and I made those negative so they stand out) > and the columns of the trace. > > Column 0 of the trace is an index into the input bits. Column 2 is > used to pick the relevant row of T, and the bit chooses one of those > two values, which then appears in column 4 of the trace. > > This works just fine, right up until the bit with index 10. There, the > bit is 1, and the relevant row from T was 1 9 and 1{1 9 should be 9, > but the trace shows that I'm getting a 1 instead. > > So either I am overlooking something critical (which I doubt ... but > it's not like i have never made a mistake, before) or there's a bug in > ;: (which might explain why other people have been discouraged from > using ;:?) > > First thing though - does this work the same way for other people? If > this behavior cannot be reproduced by some else, that introduces a > whole different line of thinking... > > Thanks, > > -- > Raul > > > On Fri, Jan 5, 2018 at 6:26 PM, Nick S <[email protected]> wrote: >> Great suggestion. I actually played with it for quite a while last night, >> got it all working. The solver can solve any puzzle I throw at it, >> including those that barely have enough definition to hold together. I can >> imagine puzzles it can't solve but those would have to be constructed to be >> unsolvable. >> >> I ended up using a lot of throws and trys and such. In some cases, the >> only exit from a routine is a set of throws with flag variables set, as in >> the example, to communicate, and it took a heck of a lot of code. In fact, >> when I start the project, it takes way longer than it used to because there >> is just way too much procedural code. >> >> I wonder just how expensive try. is. I used to get solutions in the under >> 2 second range. Now I am getting solutions in the 3.5 second range. But >> this seems to be totally based on the amount of processing. My first >> solutions were solved without trial placement or backtracking, but the long >> solutions require trial placement and backtracking. I just checked one of >> my old testcases and it is still under 2 seconds cpu for a solution. >> >> I also have hand coded backtracking, so that I can execute a trial solution >> and easily give it up when it goes nowhere. >> >> J makes it easy to create relatively complex data structures (like stacks >> for backtracking environments). I ended up with a lot of code but most >> other languages would have required five times as much code. >> >> My basic concept was that I kept a recursion count. and in my try./catcht/ >> I used the entry level to control what I did - generally at any level where >> I recursed, I would just throw. again and at the entry level I would put >> out an error message and then return. So I don't get error messages when I >> pick up the uncaught throw. Now I am catching all my throws and always >> reporting errors or successes from the top level. >> >> I appreciate all the advice I got while writing this. I will work on it a >> bit more to clean up the messages and any other bugs I find. But I have >> entered about 15 test cases, and it seems to be able to solve them all. >> >> I have used a lot of if-then-else and case logic. I know, I should be >> writing all this stuff as tacit one liners. But I don't see how. For >> example, given the length of a boolean vector as 20, is there a way to >> return all of the possible placements of three groups of 1's with length >> of 3, 4, and 5, always in that order, and with at least one zero between >> them? There can be zero or more zeros between the placements and the wall. >> In other words, all the vectors that, when converted to a character string, >> match this regular expression: >> >> ^0*1{3}0+1{4}0+1{5}0*$ >> >> 0 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 matches >> >> 1 1 1 1 0 0 0 1 1 1 1 0 1 1 1 1 1 0 0 0 does not. The first group is too >> long. There are a very large number of possible wrong solutions, but there >> are also a large number of valid solutions. >> >> I could not figure out how to do it - so I ended up writing a recursive >> routine where I place the first piece and then pass the rest of the work (a >> shortened string and fewer placements) to the recursive call. The routine >> has the advantage of letting me do early pruning of solutions where what I >> have already placed violates constraints, and so forth. And I never have >> to generate a huge binary table, just to filter and compress it to get the >> results that I need for the solution. >> >> I tried using adverse. For me it was a miserable failure - I didn't >> realize that (u y)::(error yy) was probably returning nouns, while adverse >> wants verbs as you showed. I have not tried using generated errors. What >> is fun about this language, for me, is that scutwork (coding loops to >> compare arrays or to move arrays) vanishes, while you can concentrate on >> the logic of your program. >> >> >> >> On Sun, Dec 31, 2017 at 11:28 AM, Ian Clark <[email protected]> wrote: >> >>> What's "normal" and what's an "error"? (Or, for that matter, a "crash"?) >>> >>> When looking for the best solution to a coding problem, we can be prisoners >>> of our emotive use of language. Way back in IBM in the 1980s I recall the >>> end-user of a bespoke app written in APL picking up the phone in fury when >>> it spat out at her the all-too-familiar APL message: >>> RANK ERROR >>> – she thought the coder was being gratuitously offensive. >>> >>> Stripped of its pejorative connotations, error recovery is just a way of >>> letting a deeply nested function escape and cut back the function stack – >>> and to do it in a way that doesn't look to the end-user like a coding >>> error. Or conversely, treating her to the sight of a raw coding error when >>> she'd appreciate a polite message geared to her needs and competency. >>> >>> I use (::) a lot for this purpose. Far from being "ugly" I think it is >>> clean and respectable, avoiding the need for (…but not precluding) a >>> cumbersome system of error diagnostics – which then needs debugging in its >>> own right. >>> >>> It also establishes a clear separation between "normal" code and >>> special-case handling (including error recovery), which lets you design the >>> former and then bolt-on as much of the latter as you need, and no more — >>> which to my mind (try./catch.) doesn't. >>> >>> Paste this into a temp script and run it: >>> ———————————————————————————————————————— >>> >>> NB. Use of (::) to escape to the session in a clean and respectable way. >>> >>> NB. Avoid tainting the escape route with disapproval >>> >>> NB. by using "general" not "normal" and "special" not "error". >>> >>> >>> myApp=: general :: special >>> >>> general=: verb define >>> general1 y >>> ) >>> >>> general1=: verb define >>> NB. nest it deeper >>> addOne y >>> ) >>> >>> addOne=: verb define >>> NB. recognise special cases... >>> if. y<0 do. @@ end. >>> if. y>99 do. @@ end. >>> NB. else handle the general case... >>> y+1 >>> ) >>> >>> special=: verb define >>> 'myApp: cannot handle the argument: ' , ":y >>> ) >>> ———————————————————————————————————————— >>> >>> Running the app… >>> >>> myApp 5 NB. handles general case ok >>> 6 >>> myApp _5 NB. rejects y<0 >>> myApp: cannot handle the argument: _5 >>> myApp 100 NB. rejects y>99 >>> myApp: cannot handle the argument: 100 >>> myApp '?' NB. forces a syntax error >>> myApp: cannot handle the argument: ? >>> >>> Now, crashing (general) by executing (@@) is not everyone's idea of "clean >>> and respectable". But worse – you can't tell a deliberate crash from an >>> accidental one, as (myApp'?') shows. >>> >>> However instead of (@@) you can signal a quasi-error with your own private >>> error number, and progressively code just the error diagnostics you need >>> into verb: (special) to report any bona-fide coding errors you haven't >>> fixed yet. >> >> >>> NuVoc explains how: >>> >>> http://code.jsoftware.com/wiki/Vocabulary/ErrorMessages#Defi >>> ning_your_own_error_conditions >>> >>> Thus you could redefine (addOne) and (special) like this… >>> >>> ———————————————————————————————————————— >>> addOne=: verb define >>> NB. recognise special cases... >>> if. y<0 do. signalErrorNumber 255 end. >>> if. y>99 do. signalErrorNumber 99 end. >>> NB. else handle the general case... >>> y+1 >>> ) >>> >>> special=: verb define >>> select. latestErrorNumber'' >>> case. 99 do. 'myApp: cannot handle y>99: ' , ":y >>> case. 255 do. 'myApp: cannot handle y<0: ' , ":y >>> case. do. latestErrorMessage'' >>> end. >>> ) >>> >>> signalErrorNumber=: 13!:8 >>> latestErrorNumber=: 13!:11 >>> latestErrorMessage=: 13!:12 >>> ———————————————————————————————————————— >>> >>> Now running the app… >>> >>> myApp 5 NB. handles general case ok >>> 6 >>> myApp _5 NB. rejects y<0 >>> myApp: cannot handle y<0: _5 >>> myApp 100 NB. rejects y>99 >>> myApp: cannot handle y>99: 100 >>> myApp '?' NB. forces a coding error >>> |domain error: addOne >>> | y <0 >>> >>> >>> >>> >> ---------------------------------------------------------------------- >> For information about J forums see http://www.jsoftware.com/forums.htm ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
