And... here's a working implementation: m345=:(,1)-:30 31 e.~(3;(0 10#:10*".;._2]0 :0))&;: 0.1 2.1 NB. start here (0 or more zeros) 1 1 NB. fail here 1 3 NB. second 1 1 4 NB. third 1 5 1 NB. first required zero 5 6 NB. optional zeros or fourth 1 1 7 NB. fifth 1 1 8 NB. sixth 1 1 9 NB. seventh 1 10 1 NB. second required zero 10 11 NB. optional zeros or eighth 1 1 12 NB. ninth 1 1 13 NB. tenth 1 1 14 NB. eleventh 1 1 15 NB. final 1 15 1 NB. optional zeros (succeed here) )
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 I could have computed that numeric array more concisely, of course, but this was how I wrote it, and it works fine this way. Thanks, -- Raul On Sat, Jan 6, 2018 at 1:00 AM, Raul Miller <[email protected]> wrote: > 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
