And... here's a more concise implementation...

next1=: (#,~(#*-.) >. 1+i.@#) 1 1 1 0 1 1 1 1 0 1 1 1 1 1 0
next0=: 0 15 15 4 4 15 15 15 9 9 15 15 15 14 14 15

m345=: (,1)-:28 29 e.~(3;1,"0~next0,.next1)&;:

Is this more readable? Well, ... I have to admit that it's still not
as concise as ^0*1{3}0+1{4}0+1{5}0*$

Maybe the right approach here would instead be to do:

require'regex'
m345=: '^0*1{3}0+1{4}0+1{5}0*$' rxeq {&'01'

Thanks,

-- 
Raul


On Sat, Jan 6, 2018 at 1:11 AM, Raul Miller <[email protected]> wrote:
> 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

Reply via email to