tomara-x / quartz

visual programming and dsp playground
https://codeberg.org/tomara-x/quartz
Apache License 2.0
36 stars 2 forks source link

prevent cycles in audio graphs #142

Closed tomara-x closed 3 weeks ago

tomara-x commented 2 months ago

+ 0 <-> 0 + for example is gonna clone the net of the first to the second and the net of the second to the first, repeat that each frame, each of them growing.. it's not a recursion explosion as this is relatively slow, but still can happen by accident and remain undetected for a while i'd like to handle it better than: don't create cyclical graphs with audio nodes, kids

dags. d'ya like dags?

tomara-x commented 2 months ago

bahahaha! we overflow the stack if you invoke np on one of them when connected in that way.

closing the white holes will stop the constant copying btw

tomara-x commented 2 months ago

ooo we overflow the stack eventually regardless.. fascinating!

tomara-x commented 2 months ago

btw, as expected, having node A connected twice to node B, and node B connected twice to A, causes the same kind of growth you'd expect from a fork bomb (much faster than A <-> B)

it needs a cool name! the grey cycle of destruction! ouroboros node!

Screenshot_2024-04-05_20-58-12

i think it can be fixed by checking the order at all the connective ops +, -, *, &, >>, |, ^, cause we only ever want to take inputs from lower orders, so we should never use inputs if their order is higher than self's. this prevents the cycle from happening, and the functional part of the graph still works

tomara-x commented 2 months ago

the ops thru, select, seq, and feedback (take node as input, modify self's node) while they still have this cyclic issue, in their case it doesn't matter because they read input and modify themselves, but their nodes don't grow, so it will never cause a stack overflow. the white holes remain open and the node is being constantly updated in this case (which makes it easy to spot) but it won't cause crashes :3

for example:

Screenshot_2024-04-05_22-22-15

it's open. every frame 1 gets assigned !(the node of 2), then 2 is assigned !(the node of 1). it's constant waste, but would be obvious, and it won't crash

tomara-x commented 1 month ago

i'd like a better solution here

removed in 800f39c

tomara-x commented 1 month ago

just leave it! it's conceptually adventurous 🤌

tomara-x commented 4 weeks ago

the witch: "what's this? changed 2 frames in a row? some's wrong! yeet all connections"

the mage: maintain an order of all entities based on connections (when they're created) VecVec\> and disallow higher order going to a lower

the fae: both sides need to be processing

the moth: every node has 1 correct order:

no connections => don't care
inputs only => max order of inputs + 1
outputs only => min order of outputs - 1
ins and outs => number between (max order of inputs) and (min order of outputs)

shut up, bitches! make the connectives unresponsive to wh opening, react to gained instead. and test the resetting, if it's not good, make ht mark the parent as gained

tomara-x commented 4 weeks ago

hmm another issue with the connectives is repetitions

this is fine Screenshot_2024-05-31_01-22-50

setting the repetitions to 10000000 wouldn't be

tomara-x commented 4 weeks ago

so something this innocent can freeze (takes a few minutes to finish and unfreeze)

Screenshot_2024-05-31_01-30-29

so even limiting the number of loops would be ineffective here, since one loop can go into another, and into another, resulting in a huge result, still causing a freeze

tomara-x commented 4 weeks ago

pretty sure that's also an issue for sum(), branch(), etc with large input arrays

tomara-x commented 4 weeks ago

hopefully those will help 67c6f4d 1eedb9a i'm thinking limit the number of nodes

tomara-x commented 4 weeks ago

e4041f4 cb8f21c

still possible to make fork bombs with - tho

image

and that's done e0b7744

tomara-x commented 4 weeks ago

it's still possible to cross the ridiculous horizon, since some nodes copy the whole input net into themselves (like seq, select, feedback, reset, and so on) combining that with repetition can still cause issues. i think [edit: after quick test: this is one of the few places where you're happy to see underruns]

another thing that might need limiting is the similar nodes ops (sum(), bus(), etc) but in testing those they just worked without issues for some reason. need investigation

tomara-x commented 3 weeks ago

stress test this. what if a lot of connectives reach their limit? can we crash it this way?

tomara-x commented 3 weeks ago

it becomes slow (understandably) but not crashes. now my only concern is if 500 is enough. i know there are ways around it (like sticking the whole thing in a kr() or similar) but still not sure

tomara-x commented 3 weeks ago

i think i'll leave it like this, if someone manages to crash it i'd like to get to know them, they ought to be mighty interesting folk!

(this is 1632 squares. each 4 of them is a 500 oscillator network. that's 408 networks)

Screenshot_2024-06-07_10-37-13

want a generic encapsulation tho (not kr)

tomara-x commented 3 weeks ago

(oom killer intervened) encapsulate is horrible.. even after adding order checking to it it's still bad because it brings back the issue with repetitions.

maybe i'll put the limit in a resource

tomara-x commented 3 weeks ago

i cried "POWER~"!