Comments (23)
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.
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.
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.
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.
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.
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.
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.
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.
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.
A keyword could also allow us to more easily add other types of actions in the future.
from nengo-spa.
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 thanutility
,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.
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.
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.
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.
I had dot
ensembles before ...
from nengo-spa.
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.
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.
I actually like the ifmax
, elifmax
idea. To me the above code seems very clear while allowing for future extensions.
from nengo-spa.
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.
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.
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:
-
Clarity about what is going on. This is why I really like the explicit
dot
(andtranslate
), and the<-
instead of the equal sign. I'm also liking that for theifmax
(and maybeelifmax
) andalways
, as it's at least a hint about how to interpret it behaviourally (in a way that something likeutility
oract
doesn't). -
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.
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.
Actually most arrow-like constructs are already Python operators in at least one direction: ->
, <=
, <<
, >>
from nengo-spa.
Related Issues (20)
- Add redirects to documentation
- Vocabulary doesn't consider algebra of its vectors
- Use Python 3 style classes
- Consider adding type annotations
- Semantic pointer names may consume all RAM when iterating/recursing HOT 2
- Support dividing a SemanticPointer by a constant float
- Support SemanticPointer operations with numpy scalars
- Master build is failing
- Fix deprecation warnings before Python 3.9 release
- Generate better names
- SPA sequence example is broken HOT 1
- Documentation should be built from latest stable release
- pytest-xdist 2 broke build HOT 1
- PointerSymbol is handling precedence incorrectly
- Change `represent_cc_identity` behaviour for `spa.State` HOT 12
- Drop Python 3.5 support HOT 1
- Minor Typo in SPA Intro User Guide spa-intro.html HOT 1
- Batch binding HOT 4
- Use xfail instead of NotImplementedError to skip tests unsupported by an algebra
- Add vector generators for vectors with arbitrary properties
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nengo-spa.