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