Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

base: Add new mechanism for function memoization #4543

Merged
merged 5 commits into from
Dec 30, 2024

Conversation

fridis
Copy link
Member

@fridis fridis commented Dec 20, 2024

This supports global (thread local) as well as local memoization using a syntax that IMHO looks nice.

say you have a function fib that performs poorly because it lacks memoization:

 fib(n) =>
   if n <= 1 then 1 else fib n-1 + fib n-2

you can now memoize this as follows

 fib(n) i32 : memoize => keep n _->
   if n <= 1 then 1 else fib n-1 + fib n-2

there are two things required: first, the function has to inherit from memoize. Second, the body has to be wrapped into a call to keep with the key and a lambda to calculate the corresponding result, which would usually just wrap the original code.

Apart from the speedup, the memoization shows up when you analyse the effects:

 > ./build//bin/fz -effects fib.fz
  ...
 fib#1.memoized i32 i32
  ...

It might be desired not to keep memoized results forever. To do so, we have to instate a local instance of the memoize.memoized effect. This can be done as follows:

 # define my own memoization effect
 my_fib_memo : memoize.memoized i32 i32 is

 # create an instance of it and instate it
 my_fib_memo ! ()->

   # now use keep from this effect. Don not forget the `.env`!
   fib2(n) => my_fib_memo.env.keep n _->
     if n <= 1 then 1 else fib2 n-1 + fib2 n-2

   # running this code shows improved performance
   (40..45) .for_each (n->say "$n {fib2 n}")

Since memoization is used locally only, the effect does not show up when effects are analysed.

 > ./build//bin/fz -effects fib.fz
  ...

NOTE: Currently, memoizaion requires keys to be orderable. Would be great
to support hashable as well

NOTE: Memoization is currently not thread safe. In case we want memoization
to be used amoung threads, we will need a thread safe variant. However,
this should currently be usable in multiple threads as long as each
thread has its own instance of memoized. We just do not profit from
values memoized in another thread.

This supports global (thread local) as well as local memoization using
a syntax that IMHO looks nice.

say you have a function `fib` that performs poorly because it lacks
memoization:

     fib(n) =>
       if n <= 1 then 1 else fib n-1 + fib n-2

you can now memoize this as follows

     fib(n) i32 : memoize => keep n _->
       if n <= 1 then 1 else fib n-1 + fib n-2

there are two things required: first, the function has to inherit from
`memoize`.  Second, the body has to be wrapped into a call to `keep`
with the key and a lambda to calculate the corresponding result, which
would usually just wrap the original code.

Apart from the speedup, the memoization shows up when you analyse the
effects:

     > ./build//bin/fz -effects fib.fz
      ...
     fib#1.memoized i32 i32
      ...

It might be desired not to keep memoized results forever. To do so, we have
to instate a local instance of the `memoize.memoized` effect. This can be
done as follows:

     # define my own memoization effect
     my_fib_memo : memoize.memoized i32 i32 is

     # create an instance of it and instate it
     my_fib_memo ! ()->

       # now use keep from this effect. Don not forget the `.env`!
       fib2(n) => my_fib_memo.env.keep n _->
         if n <= 1 then 1 else fib2 n-1 + fib2 n-2

       # running this code shows improved performance
       (40..45) .for_each (n->say "$n {fib2 n}")

Since memoization is used locally only, the effect does not show up when
effects are analysed.

     > ./build//bin/fz -effects fib.fz
      ...
     fib#1.memoized i32 i32
      ...

NOTE: Currently, memoizaion requires keys to be orderable. Would be great
      to support hashable as well

NOTE: Memoization is currently not thread safe. In case we want memoization
      to be used amoung threads, we will need a thread safe variant. However,
      this should currently be usable in multiple threads as long as each
      thread has its own instance of memoized. We just do not profit from
      values memoized in another thread.
@fridis fridis added enhancement New feature or request base library related to the Fuzion base library labels Dec 20, 2024
@michaellilltokiwa michaellilltokiwa merged commit c9f8701 into main Dec 30, 2024
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
base library related to the Fuzion base library enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants