Recompute only when changed

Hi,
I’m looking for a way how to prevent recomputing items in the list which didn’t changed. I have a list of n input parameters for time-consuming components, I know that only one item in the list will change so I don’t need to recompute others. At the end, I would like to have a list of solutions again.

Something like this (done only for item 3):

My idea is something like this:

 private void RunScript(object x, ref object A)
 {
    if(x != remeber)
    {
      // recompute
      results = GetResult(x);
      remember = x;
      A = results;
    }
    else
    {
      // do not recompute;
      // A = results;
      // this.IsNotExpired;
    }
  }

  // <Custom additional code> 
  object remember = null;
  object results = null;
  // </Custom additional code> 
}

Try this:

using System.Threading.Tasks;
using System.Linq;

private void RunScript(List<double> x, ref object A)
  {
    Parallel.For(0, x.Count, i => {
      //for(int i = 0;i < x.Count;i++){
      if(x[i] != MemInputs[i]){
        // x[i] value is different from last execution, storing the new value and executing the "time consuming code"
        MemInputs[i] = x[i]; // Storing
        MemOutputs[i] = TimeConsumingMethod(MemInputs[i]);
      }
      //}
      });
    A = MemOutputs.Take(x.Count).ToArray();
  }
  // <Custom additional code> 
  // Preallocate abundant-enough arrays
  public double[] MemInputs = Enumerable.Repeat<double>(-959.7, 100).ToArray(); // using random value (-959.7) to trigger the != operator
  public double[] MemOutputs = new double[100];

  public double TimeConsumingMethod(double d){
  return d+1;
  }
  // </Custom additional code>

Nice. That is mostly what I was looking for. The only problem is that TimeConsumingMethod() have to be some other components in Grasshopeer (even worse from plugin). So I am facing another problem how to use node-in-code for plugin components (in my case Dendro) or how to do it different way.

Are you sure you can’t isolate your source data each in its own parameter instead of putting them together in the same panel, so that only the downstream components of each changed source are recalculated?

The thing is if you put them together, all its downstream components will be expired when this is expired (when you change one of its values), because is how GH works. I guess this can be changed in a custom component but no from an scripting component.

Unfortunately that will be very difficult. I have a own component which is creating that list (actually it is a tree but, I guess, it will not influence it a lot). I think the way to go could be the two components on both sides of time consuming code where:

  1. component will pass only data which have to be recomputed and their Path info.
  2. component will collect recomputed results and combine them with stored data from the past.

Like this:

This way only new data will be recomputed, I guess. I’m going to code it and post it here if succesfull.

If scripting is not useful… then what about this:

0- Graft everything, making every object a separate branch
1- use a 0.25sec late DataDam to check which object changed
2- dispatch everything but what is needed to recompute, so feeding nulls + what needed to the “Heavy step”
3- ignore null outputs completely and record (with record limit=1)
4- Trim tree

Better than 1000 words:


asdasd.gh (10.5 KB)

Edit:
add a button to make it run all at once the first time:
2021-05-24 16_52_49-Grasshopper - asdasd_

Here is my solution:


Recompute_Changes_Solved.gh (6.5 KB)

There are two C# scripts one passing only changed data, another one adding/replacing results.
it works on tree branches instead of lists, so it is passing whole branches that changed from last time. So it is a bit different from my initial question, but closer to my real problem.

I’m going to check @maje90 solution (above) later.

1 Like

Wow!
The logic is very similar to what I did with simple blocks but your code is much cleaner!
Well done!

I don’t know if your “Time consuming code” works with single items or with lists, but if with single items you should similarly do a global graft before the first c# and a trim tree after the second c#.
Currently your script update the whole branch if you change a single item…

Also, problem on your and mine solution: the data recorder or your second c# do not “forget” paths that are no longer used.
On my solution it would need resetting the recorder and recomputing everything, on yours you could pass the datatree structure size (which branches exist and how much long are) from first c# to second…

Anyway, well done!! :star_struck:

For me, it is really fascinating to see that something like this is possible without a line of coding. Amazing :clap:.

I tried to solve a problem with “not forgetting” paths and here is my solution:


Recompute_Changes_Solved.gh (8.4 KB)

  • I added “Reset” input to the first component which will force to recompute all data.
  • The second component I completely rewrote. Now it takes a second input which serves as a template for tree structure and the Component itself adds/removes Paths based on that template. It definitely could be written better, but it serves its purpose for now.

What I’m struggling with is to make is generic datatype, now it strictly requires double type.

1 Like