AVX has been added to processors on PCs. As a result many scalar (rank 0)
verbs now can process entire arrays in hardware. So, given something like:

   (test x) *. (f x)

(test x) can be performed in hardware vector mode, but in order to skip
performing the calculations (f x) where the results of (test x) are zero it
would be necessary to first compress x, using the results of (t=.test x) as
a mask. Then apply(f t#x) with vector hardware. Then reinsert the zeros to
get the final result.

Whether this would be more efficient than just performing (f x) on the
entire x then zeroing those where (test x) is zero depends on the
complexity of computing (f x).

The problem with trying to save time by skipping (f x) where (test x) gives
zeros is scalar thinking. Which is correct on scalar processors and scalar
languages like C. But soon I'm sure constructs will be added to C (if not
already) that exploit AVX. Then the scalar approach even in C becomes
questionable.

One of the beauties of J is that it is not necessary to add new constructs
to support AVX. New concepts in hardware will continue to come out. We have
no idea what they will be years from now. But what works well in today's
(or yesterday's) hardware may not in the future.

The design of J seems well adapted to implement support for new hardware in
the J engine without requiring changes to J source.

On Tue, Nov 7, 2017 at 6:24 AM, Erling Hellenäs <erl...@erlinghellenas.se>
wrote:

> Hi all!
>
> I did not write the post because I want information about the J
> interpreter but to describe why *. can not be used as an if structure.
> I welcome comments about what is wrong with the text, but what I mainly
> expect is that responders look at the meaning of my post and the question
> we discuss and continues with this discussion.
>
> Cheers,
> Erling Hellenäs
>
>
> Den 2017-11-07 kl. 13:58, skrev Raul Miller:
>
>> (quoted thoughts itemized and numbered here so I can respond to them
>> individually)
>>
>> EH 1> The verbs are passed only noun arguments. There is no functional
>> left argument to *. which the verb could omit to execute.
>>
>> As a simplifying assumption, this has been true, largely because of
>> the parsing rules. That said, Jose has illustrated some cases where
>> it's possible to circumvent this.
>>
>> EH 2> The parser curries the program. The interpreter does not see any
>> brackets which it could omit executing.
>>
>> I would not make a distinction between the parser and the interpreter.
>> Currying is also a term which may or may not apply to otherwise
>> similar trains handled by the parser.
>>
>> EH 3> The parser works from left to right, the interpreter from right
>> to left. The parse result is list of pointers to nouns and verbs that
>> is interpreted/executed from right to left.
>>
>> The lexer works from left to right. The parser works from right to
>> left as documented here:
>> http://www.jsoftware.com/help/dictionary/dicte.htm
>>
>> While you can identify list structures in a variety of things
>> generated by the parsers (arrays, for example, can be said to have
>> list structures), using the terminology that way is more shoehorning
>> the J design into a terminology framework oriented around other
>> languages.
>>
>> EH 4> The parser reads the statement until the first bracket start,
>> the bracket contents are then parsed and interpreted/executed, the
>> resulting noun is packed for later interpretation. All brackets are
>> handled this way recursively until the end of the statement. Then the
>> statement is interpreted/executed.
>>
>> Sort of, but no:
>>
>> Yes, content of parenthesis gets evaluated before its immediate
>> context can finish being evaluated, but parsing is interpretation /
>> execution. When parsing has completed on a sentence, that sentence has
>> a single result which may be a noun (array), verb, adverb or
>> conjunction.
>>
>> That said, when a derived verb (or adverb or conjunction) executes, it
>> may not need further use of the parser (if it does, that's where the
>> recursion would come in - other than that, the parser is not recursive
>> - instead it is iterative with an explicit stack data structure).
>>
>> EH 5> The difference in the tacit case is that the execution is
>> delayed. The bracket contents are packed in a composition, a new verb,
>> a "single verb", which is executed by the nearest explicit parent
>> statement. The pointer to this new verb is included in the list to be
>> parsed, instead of it's noun result.
>>
>> Sort of - see above.
>>
>> EH 6> *. in J is a scalar verb. All it receives is its scalar
>> arguments. It could in theory omit executing the And if the right
>> argument is zero, however, you would need an if statement and a
>> comparison to do that and doing the And immediately is cheaper.
>>
>> I am not sure what you mean by "scalar". If you mean "rank zero", you
>> are correct.
>>
>> I am also not sure what you mean by "receive" - there are at least two
>> potentially relevant "receive" concepts here - the rank 0 concept
>> (handling the individual numbers) and the rank wrapper concept
>> (handling the array structures).
>>
>> That said, trying to break the rank mechanism to borrow "short
>> circuit" evaluation from other languages would... break the rank
>> mechanism.
>>
>> EH 7> Then there is a "hidden" rank-like program handling all scalar
>> verbs. This program takes noun arguments and references to the scalar
>> verb. What it executes is the C/C++ code corresponding to the scalar
>> verb. The scalar verb does not actually exist as an entity. There are
>> several corresponding entities - C/C++ programs. One for each type
>> combination. This "hidden" rank-like program is highly optimized and
>> it is very important to keep special cases out of it.
>>
>> Assuming I understand what you mean by "scalar verb", the scalar verbs
>> actually do exist as entities, internal to the interpreter - these are
>> used to implement the visible behavior of the system.
>>
>> Specifically, for *. the interpreter defines four "scalar verb"
>> functions which are used in its implementation. You can see their
>> declarations here:
>>
>> https://github.com/openj/core/blob/master/ve.c#L132
>>
>> You can see the  definition of the APFX macro (which provides the bulk
>> of the function body) here:
>> https://github.com/openj/core/blob/master/va.h#L154
>>
>> I could go on, but hopefully this is enough to show you this aspect of
>> the implementation.
>>
>> I hope this helps. (But I am not sure it will help enough - I know I
>> have repeated some of these concepts many times already - in
>> particular the parsing process - so maybe there is something wrong
>> with how I try to express these concepts?)
>>
>> To see the execution steps performed by the parser, I recommend using
>> J's trace facility.
>>
>> For example, please try this:
>>
>>     require'trace'
>>     trace'(2*3)+5'
>>     trace'2*3+5'
>>
>> Each block displayed will contain up to five newline separated items:
>>
>> (*) a separator line identifying the relevant rule from the parsing
>> and execution appendix of the dictionary --
>> http://www.jsoftware.com/help/dictionary/dicte.htm
>>
>> (*) two or three lines identifying the relevant parsing entities
>> (nouns, verbs, adverbs, conjunctions or punctuation) being evaluated
>> in this parsing step. These correspond to the bolded items from the
>> table of that appendix.
>>
>> (*) the result of that evaulation
>>
>> If parsing completes successfully there will be a
>> ============================== line followed by the final result
>> (which will be the same as the result of the final evaluation).
>>
>> Again... I hope this helps.
>>
>> Thanks,
>>
>>
> ----------------------------------------------------------------------
> 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