Replies: 12 comments 34 replies
-
Thanks for working on this. Did a little search, and it seems there aren't many reactive frameworks that are well maintained. So purely based on that, would point me in either going with Solara or our own implementation (or some hybrid). |
Beta Was this translation helpful? Give feedback.
-
You have PySignal and psygnal. I used the latter in the example, and its last commit was 2 months ago. |
Beta Was this translation helpful? Give feedback.
-
I really like this, thanks for the effort! I had my reservations in the past, but now I think its actually a good pattern. I especially like the evented containers of psygnal and the possibility to force runtime type checking, which just seems to be helpful things to have overall. I would like so see an implementation of this, which is not yet coupled to datacollection or anything else. |
Beta Was this translation helpful? Give feedback.
-
I looked at psygnal's API. It seems that one emits a value, which is then consumed by the subscribers. But how can I access the current value of the signal object, multiple times (could be in a loop)? In Solara I can do this: counter = solara.reactive(0)
counter.value += 1000
for i in range(10):
print(counter.value)
# Or do other data collection, visualization, etc. In psygnal, the only way to do this is to emit to a container which value is then read multiple times. But the killer feature of Solara's |
Beta Was this translation helpful? Give feedback.
-
What should be covered by a draft implementation? I see a few things that would together offer a good starting point
class Agent:
wealth = Observable(int)
income = Observable(int)
def wealth_callback(wealth):
print(f"new wealth is {wealth}")
def income_callback(income):
print(f"new income is {income}")
def my_callback(signal):
print(signal)
agent = Agent()
agent.signals.connect(my_callback) # is called whenever either wealth or income is changed
agent.wealth_change.connect(wealth_callback) # only called when wealth is changed
agent.income_change.connect(income_callback) # only called when income changes Here Any other ideas are welcome. |
Beta Was this translation helpful? Give feedback.
-
I think your 3 points are a nice pathway that we could follow along starting with 1) An open question was how to deal with mutable objects. I believe evented containers should cover 99% of that. We should still have a solution for other arbitrary objects, but this could very well just be an exception stating that such objects cannot be used for Observables. |
Beta Was this translation helpful? Give feedback.
-
This looks a lot like the signal/slot mechanism in Qt, a C++ GUI framework: https://doc.qt.io/qt-6/signalsandslots.html. It also has a python binding: https://doc.qt.io/qtforpython-6/tutorials/basictutorial/signals_and_slots.html
I think this will be very useful for those who are unfamiliar with Mesa or programming in general. For instance for a model class BoltzmanWealthModel:
gini = Observable() Instead of model = BoltzmanWealthModel()
SolaraViz(
model,
components=[mesa.visualization.make_plot_measure("gini")]
) we can simple write model = BoltzmanWealthModel()
# two plots will be made: 1) a default space plot, 2) a default measure plot
SolaraViz(model) since Looking forward! |
Beta Was this translation helpful? Give feedback.
-
I have opend a PR: #2291. This is a first draft with a slightly refined version of the code outlined above. Feedback is very much welcome. |
Beta Was this translation helpful? Give feedback.
-
I would like to dive a bit deeper into the observables vs signals debate. What I find super intriguing about signals how I know them is that they usually also provide a reactive context in which they auto-subscribe to other signals. Let me show what I mean (classic example of reactive programming) # Pseudo-code
a = Signal(2)
b = Signal(a + 3)
print(b) => 5
a = 5
print(b) => 8 Do you think something like that might be feasible? This is how it would look like in Vue (JavaScript) const a = ref(2)
const b = computed(() => a.value + 3)
console.log(b.value) (Just to show possible semantics. here is how it works in solara. |
Beta Was this translation helpful? Give feedback.
-
Sorry for being late to the party but this is awesome!!! I know Rob Axtell was heavily looking into ways to figure out how to do datacollection on large (e.g. 20 million or more agents) as the data just becomes too much. This to me represents the most promising approach. Also, I think if we get clever this can be critical for identifying phase transition, attached is some work I was following by Marten Scheffer, where it seems like there may be universal signal signature between nodes in a complex adaptive system that represents when the system is about to hit a bifurcation point . |
Beta Was this translation helpful? Give feedback.
-
TLDR: Its traitlets. We have been discussing traitlets the whole time Its fascinating how having a good terminology can make such a difference. Taking away the recent discussions about "computed" properties the "Observable" class discussed here is just IPythons tratilets. from traitlets import HasTraits, Int, observe
class Model(HasTraits):
steps = Int(0, help="The number of steps the model has taken")
....
model = Model()
def func(change):
print(change)
model.observe(func, names=["steps"])
model.step()
# prints {'name': 'steps', 'old': 0, 'new': 1, 'owner': <mesa.model.Model object at 0x000002496FE93D70>, 'type': 'change'} It also supports the |
Beta Was this translation helpful? Give feedback.
-
I briefly mentioned it yesterday, but I thought and read about it a bit more and decided it's worth it's own thread in this discussion. I think param is really amazing! I don't have the time right now to talk more about it or give code examples, but if someone has time over the weekend definitely check it out! Yes, it has serious performance implications it seems. But we probably should investigate this on a more complete example and also think about if this still isn't worth it. We could unlock some more design patterns and we now have mesa-frames for high performance needs. |
Beta Was this translation helpful? Give feedback.
-
I, at long last, have picked up the work on pub/sub and data collection. In the meantime, many things have changed in MESA, and good suggestions have been made on data collection and libraries that might be worth a look. Let me first try to summarize the idea.
Motivation and background
At the moment, the visualization piggybacks on the data collection. Ideally, however, MESA should offer a way of declaring at the Agent/Model level that given attributes are of interest and to be tracked by data collection and/or a GUI. This would more cleanly separate data collection and visualization and thus result in a cleaner separation of concern. Moreover, @Corvince suggested to potentially automate default datacollection. Again, this requires some way for the user to declare what data should be collected. Pub/Sub, Signals, or whatever you which to call it is a suitable design pattern for providing this mechanism.
Also, I have gotten stuck with some of my earlier work on this by trying to solve the data collection and this pub/sub stuff in one go. It might be more fruitful to approach this as has been happening with the AgentSet. First, add a simple working thing and see how it grows and can be used to solve various problems in MESA.
API considerations
Ideally, the API for declaring attributes as being of interest to something outside the model is simple. This is why I have been advocating the use of descriptors. This would allow the user to just add at the top of the class definition which attributes are of interest, and the rest is taken care of by MESA. This gives a very simple declarative API. The API would be
Here, Observable is the descriptor that declares
wealth
andgini
to be of interest to be tracked by, e.g., a visualization or data collection mechanism. The name is, of course, open for discussion. Ideally, this Observable descriptor behind the scenes handles all the other magic that allows one to subscribe to changes in the value ofgini
orwealth
, as well as emiting/firing/sending a message/signal whenever there is such a change.This other magic, however, involves at least 2 things
So, I want to be able to do something like
Technical considerations
There are at least 3 options that I see for implementing this
I have started digging more into psygnal. Psygnal is a very nice library with many desirable features. For example, it is possible to temporarily pause the firing of signals. It also comes with support for various python containers. So, if you add an item to the list, a message will automatically be emitted. I can implement a minimum working version of the envisioned API quite easily with psygnal:
Next Steps
Beta Was this translation helpful? Give feedback.
All reactions