Giter VIP home page Giter VIP logo

Comments (23)

jgosmann avatar jgosmann commented on August 28, 2024 2

I'm not entirely a fan of sink <- source. It read's backwards to me. I think it's more intuitive to do source -> sink?.

I agree. I would also be fine with supporting both variants.

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024 1

Here's another option, which might be getting a bit crazy:

ifmax dot(vision, WRITE + SAY):
    verb <- vision
elifmax dot(vision, YES+NO+HI+BYE+OK):
    noun <- vision
elifmax dot(phrase, VERB*WRITE) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
    hand <- phrase*~NOUN
elifmax dot(phrase, VERB*SAY) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
    speech <- phrase*~NOUN
always:
    phrase <- verb*VERB + noun*NOUN

(the reason for doing the elifmax would be that you could also start another block of ifmax/elifmax statements, which would be implemented with a separate BasalGanglia (which, biologically, would just be one of the other tracts through the basal ganglia). Then again, you can already do that just by having a separate spa.Actions, which may be a lot clearer than doing it this way....

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

Give #63 I feel that the usage of the equals sign in more of a problem because the rest of the action rule language ends up being much closer to normal Python. To me a syntax like

  • sink <- source
  • sink <-- source
  • source -> sink
  • source --> sink

seems much better (potentially even allowing both directions of the arrow) as it highlights more the graph structure and direction of information transmition. However, that requires to change the syntax of the basal ganglia utility value (currently using -->) which is very similar (or identical) to this. So far I don't have very many ideas. Potentially a colon : could work, but is more easily overlooked: utility: source -> sink.

Tagging @astoeckel (who initially brought this issue up, I believe) and tagging @tcstewar who's opinion is always welcome in SPA questions.

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

I really have no idea on this one... :( But I do like the idea of shaking up the syntax a bit. The current --> syntax was mostly stolen from ACT-R, so there's no great reason to keep it....

I wonder if we could also bring in some indenting to help with this? And also to help with complex action rules starting to become unreadable? I'm thinking something like this:

Current approach:

    actions = spa.Actions([
        'dot(vision, WRITE+SAY) --> verb=vision',
        'dot(vision, YES+NO+HI+BYE+OK) --> noun=vision',
        'dot(phrase, VERB*WRITE) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK)'
            '--> hand=phrase*~NOUN',
        'dot(phrase, VERB*SAY) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK)'
            '--> speech=phrase*~NOUN',
        'phrase = verb*VERB + noun*NOUN',
        ])

Alternate approach:

    actions = spa.Actions('''
        dot(vision, WRITE + SAY):
            verb <- vision
        dot(vision, YES+NO+HI+BYE+OK):
            noun <- vision
        dot(phrase, VERB*WRITE) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
            hand <- phrase*~NOUN
        dot(phrase, VERB*SAY) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
            speech <- phrase*~NOUN
        phrase <- verb*VERB + noun*NOUN
        ''')

Hmm, now that I write that out, I kinda like it... I very much like having the : and indentation thing be the same as normal python... and I like having it all as one multi-line string....

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

Interesting idea! What do you think should happen if someone nests the utility statements?

dot(vision, WRITE):
    verb <- vision
    dot(audition, YES + NO + BYE + OK):
         noun <- audition
    dot(audition, STOP):
        state <- audition

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

What do you think should happen if someone nests the utility statements?

Hmm.... too many options for what that could mean, I think, so I'm tempted to just say that no, it's not allowed....

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

I think I would add a “keyword” to make it a bit more pythonic:

    actions = spa.Actions('''
        utility dot(vision, WRITE + SAY):
            verb <- vision
        utility dot(vision, YES+NO+HI+BYE+OK):
            noun <- vision
        utility dot(phrase, VERB*WRITE) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
            hand <- phrase*~NOUN
        utility dot(phrase, VERB*SAY) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
            speech <- phrase*~NOUN
        phrase <- verb*VERB + noun*NOUN
        ''')

Maybe even be more explicit about cortical rules (this could be optional):

    actions = spa.Actions('''
        utility dot(vision, WRITE + SAY):
            verb <- vision
        always:
            phrase <- verb*VERB + noun*NOUN
        ''')

I think I would also like to include the naming of rules into that syntax. Maybe something like:

    actions = spa.Actions('''
        utility dot(vision, WRITE + SAY) named 'vision-rule':
            verb <- vision
        always 'cortical-connection':
            phrase <- verb*VERB + noun*NOUN
        ''')

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

I think I would add a “keyword” to make it a bit more pythonic:

Hmm... I'm not sure that ends up being more pythonic... it just ends up looking like visual clutter to me... maybe something shorter like act or action? Although even that's not all that pythonic as those are verbs/nouns, rather than closed-class function words.... I'm not sure that a keyword is needed here... hmm....

Maybe even be more explicit about cortical rules (this could be optional):

I was also tempted to put in exactly that always: for the cortical rules, and I like that it's a closed-class word that's pretty unlikely to cause naming conflicts.

I think I would also like to include the naming of rules into that syntax. Maybe something like:

I'd stick with the Python as for this, rather than named. :)

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

I'm not sure that ends up being more pythonic...

Everyline in Python that ends with a colon will start with a keyword (only exception dictionary definitions). Without a keyword it look to me like an evaluation that isn't used or assigned to anything, it might make parsing harder (the parser would have to look for colons at the end of the line, but colons might appear at the end of the line for other reasons). action is only one letter shorter than utility, act might be a bit cryptic. Also, cortical rules are also actions.

I'd stick with the Python as for this, rather than named. :)

I could see that ... but as produces a variable, not a string that can be used as a reference in Python. However, with the inspective parsing it might be possible to assign the action rule object to an actual variable ...

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

A keyword could also allow us to more easily add other types of actions in the future.

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

Everyline in Python that ends with a colon will start with a keyword (only exception dictionary definitions).

True. I think what I meant to say is that I don't find it more usefully pythonic to have that keyword there. Or at least I don't feel like anything is missing there. After all, the <- isn't pythonic at all. I guess what it comes down to is the "Without a keyword it look to me like an evaluation that isn't used or assigned to anything" part. I don't get that feeling. So this might be something where we have to see what other people think...

it might make parsing harder (the parser would have to look for colons at the end of the line, but colons might appear at the end of the line for other reasons).

What other reasons are you thinking of? I can't think of any way that there could be a : in this code other than these end-of-line markers.

action is only one letter shorter than utility, act might be a bit cryptic.

Looking at all of those options, I think I'm most worried about the naming conflict possibilities. All of those are reasonable names for spa.State objects, and that would just get confusing. If we really had to have a keyword, I think then I'd maybe argue for if, but I'm not sure we do....

I could see that ... but as produces a variable, not a string that can be used as a reference in Python. However, with the inspective parsing it might be possible to assign the action rule object to an actual variable ...

I think that's going to far down the black-magic route, and trying to tie it too closely to Python. I was just saying that as is a perfectly good thing to use rather than named, as it has pretty similar meaning, and is guaranteed to not cause variable name problems.

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

After all, the <- isn't pythonic at all.

Why not? With pythonic I doesn't mean that it is something that currently exists in Python (because obviously we are extending the language), but something that follows common prinicples in Python. <- would just be a new, special operator.

What other reasons are you thinking of?

We're using Python eval to parse the rules, so someone could do something like sink <- translate(**{'source': source, 'vocab': vocab}). Probably no one will ever want to do that, but I'd prefer to not break this part of parsing without a very good reason.

Actually, there might be good reasons to use : as end of line marker, but not in a utility value definiton:

spa.Action('''
    if model_variant_a:
        a <- b
    else:
        a <- c
    for selector, source in zip([A, B, C], [a, b, c]):
        utility dot(stimulus, selector):
            state <- source
    ''')

Not sure how easy it would be to make this work and whether it is a good idea ...

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

I think I'm most worried about the naming conflict possibilities

We have the same problem with the “built-ins” (dot, translate, reinterpret). If we didn't have those, I would be more inclined to avoid adding one or two more reserved words.

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

Why not? With pythonic I doesn't mean that it is something that currently exists in Python (because obviously we are extending the language), but something that follows common prinicples in Python. <- would just be a new, special operator.

Possibly. I just feel that "not having a keyword in front of a statement ending in a colon" is better than "adding a keyword that must be typed at the beginning of every action line and might conflict with existing objects". But, that's starting to get into very subjective territory, and I don't particularly trust my own judgement on these things and would want to see how other people feel. :)

We have the same problem with the “built-ins” (dot, translate, reinterpret). If we didn't have those, I would be more inclined to avoid adding one or two more reserved words.

All the more reason to keep these to a minimum. And it does help a lot that translate and reinterpret are verbs (and relatively long verbs at that) so they have a pretty low chance of having naming conflicts. And dot is at least a relatively common programming operator and also unlikely to have naming conflicts other than with np.dot. But I'm pretty sure I've built models with a utility ensemble, an act ensemble, and an action ensemble.....

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

I had dot ensembles before ...

from nengo-spa.

astoeckel avatar astoeckel commented on August 28, 2024

Just to add my two cents: I agree that having <- or <-- for sink <-- source is a good idea. I also like the idea of structuring the action rules in a more Phytonic way. What I'm still not comfortable with is the fact that it isn't apparent to the average programmer what is going on here: it isn't made explicit that we're actually selecting between a set of utilities and picking the one with the maximum utility.

So I'd propose something more along these lines, though I'm not 100% sure whether this is practical:

ismax dot(vision, WRITE + SAY):
    verb <- vision
ismax dot(vision, YES+NO+HI+BYE+OK):
    noun <- vision
ismax dot(phrase, VERB*WRITE) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
    hand <- phrase*~NOUN
ismax dot(phrase, VERB*SAY) - 2*dot(vision, WRITE+SAY+YES+NO+HI+BYE+OK):
    speech <- phrase*~NOUN
otherwise:
    phrase <- verb*VERB + noun*NOUN

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

Interesting... I like the idea of indicating the operation here... (one minor error: that last one should be always, not otherwise). Other options for ismax might be ifmax or oneof?

from nengo-spa.

astoeckel avatar astoeckel commented on August 28, 2024

I actually like the ifmax, elifmax idea. To me the above code seems very clear while allowing for future extensions.

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

We're using Python eval to parse the rules, so someone could do something like sink <- translate(**{'source': source, 'vocab': vocab}). Probably no one will ever want to do that, but I'd prefer to not break this part of parsing without a very good reason.

Okay, that is disturbingly beautiful... I hadn't thought of that at all.... :) Hmm... so I guess it ends up being one of those "find the colon at the end of a line that is outside of any nested parentheses, brackets, or braces" algorithms.... which I think would work.... The only non-line-ending colon that's not nested like that that I can think of is the colon for a lambda, but since you'd have to call the function it'll need to be nested inside parentheses.... I'm thinking of something pathological like this:

ifmax dot(state, DOG)*(lambda x:
                   x**2)(0.5)):
    state <- CAT

from nengo-spa.

xchoo avatar xchoo commented on August 28, 2024

I'm not going to get too involved in this thread but here are some things to consider:

The ifmax syntax is neat, but it reminds me very much of the old def ... syntax from the spa module in Nengo 1.4. That was dropped in favour of the current syntax for a reason (can't remember why. @tcstewar might have a better idea), but that reason should be taken into account when designing the new system.

I'm not entirely a fan of sink <- source. It read's backwards to me. I think it's more intuitive to do source -> sink?.

from nengo-spa.

tcstewar avatar tcstewar commented on August 28, 2024

The ifmax syntax is neat, but it reminds me very much of the old def ... syntax from the spa module in Nengo 1.4. That was dropped in favour of the current syntax for a reason (can't remember why. @tcstewar might have a better idea), but that reason should be taken into account when designing the new system.

The old def system was an attempt to do it all as normal Python, rather than as a separate string. So that put very strong restrictions on the syntax, in that it had to by valid Python code. In other words, I was doing this:

def action_a(state='A'):
    state='B'

rather than:

ifmax dot(state, A):
    state <- B

(and then doing a bunch of Python black magic to make all that work). The def syntax forced the use of the = sign, both for comparison (now dot) and for the routing information (maybe now <-).

Anyway, that was the main reason for me to step away from the old def syntax. So I think with this version, where it's done as a separate string but with as-Python-like-as-possible syntax (and using eval in the local context to process it so you have access to your local variables), I think we're avoiding the syntax restrictions nicely.

For me, the two biggest goals for this new system would be:

  1. Clarity about what is going on. This is why I really like the explicit dot (and translate), and the <- instead of the equal sign. I'm also liking that for the ifmax (and maybe elifmax) and always, as it's at least a hint about how to interpret it behaviourally (in a way that something like utility or act doesn't).

  2. Simplifying the syntax, especially for multi-line actions. For example, last month I wrote this set of Actions:

    speed = 0.3
    separation = 0.3
    strength = 0.4
    actions = spa.Actions(
        'dot(rule, (BELOW-ABOVE-LEFT-RIGHT)*V)*{strength} +'
        '(subjy - objy)+{separation} --> '
                 'status=BAD, '
                 'objs=-{speed}*Y*objs*~S + {speed}*Y*objs*~O'.format(**locals()),
        'dot(rule, (BELOW-ABOVE-LEFT-RIGHT)*V)*{strength} +'
        '(subjy - objy)-{separation} --> '
                  'status=GOOD'.format(**locals()),
    )

My hope is that could be made a bit nicer, turning into something like:

    speed = 0.3
    separation = 0.3
    strength = 0.4
    actions = spa.Actions('''
        ifmax dot(rule, (BELOW-ABOVE-LEFT-RIGHT)*V)*strength +
              (subjy - objy)+separation:
                 status <- BAD
                 objs <- -speed*Y*objs*~S + speed*Y*objs*~O
        ifmax dot(rule, (BELOW-ABOVE-LEFT-RIGHT)*V)*strength +
              (subjy - objy)-separation:
                 status <- GOOD
       ''')

I didn't think that it'd be at all possible to have those local variables accessible in the parsing until @jgosmann came up with this "inspective parsing" approach.... To me that lets us adjust the syntax in some interesting ways, while still keeping access to normal python variables and whatnot.

Anyway, not sure if all that helps, but it's what I'm thinking about this at the moment. :)

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

I spent some time on writing a tokenizer/lexer for the new action rule syntax, rewriting my partial solution once to improve it, and still ending up dissatisfied. Now I discovered the standard library module tokenize that gives access to a complete tokenizer for Python. 😃 Because it's only lexing it doesn't care about new keywords etc.

While playing around, I noticed that -> is already a valid operator in Python 3 for function annotations. This leads to the question whether we should better come up with a different operator to avoid that double meaning? (Though function definitions won't be possible in the action rules for now.)

from nengo-spa.

jgosmann avatar jgosmann commented on August 28, 2024

Actually most arrow-like constructs are already Python operators in at least one direction: ->, <=, <<, >>

from nengo-spa.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.