# Memoizing a function using only a subset of arguments as an identifier

**URL:** https://discourse.julialang.org/t/memoizing-a-function-using-only-a-subset-of-arguments-as-an-identifier/107426
**Category:** General Usage
**Tags:** question, memoize
**Created:** [December 11, 2023, 10:38am UTC](https://discourse.julialang.org/t/memoizing-a-function-using-only-a-subset-of-arguments-as-an-identifier/107426 "2023-12-11T10:38:03Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![Aleksandr\_Mikheev](https://avatars.discourse-cdn.com/v4/letter/a/b4bc9f/32.png) [@Aleksandr\_Mikheev](https://discourse.julialang.org/u/Aleksandr_Mikheev)
#### Post date: [December 11, 2023, 10:38am UTC](https://discourse.julialang.org/t/memoizing-a-function-using-only-a-subset-of-arguments-as-an-identifier/107426/1 "2023-12-11T10:38:03Z")

</div>

Suppose I have a function of two arguments. For instance,

```julia
function foo(a::Float64,b::Float64)
   return a^2 - b
end

```

Is it possible to memoize it based on the first argument only? I understand how I can partially achieve this goal:

```julia
using Memoization

function foo(b::Float64)
   @memoize function f(a::Float64)
      return a^2 - b
   end
end

```

Now I can just define `g1 = foo(1.0)`, `g2 = foo(2.0)`, etc. But it seems there should be a more elegant way to get what I want, such that I don’t need to define a new function for every ‘dummy’ argument.

Also, just as a reference, here’s the [stackoverflow thread](https://stackoverflow.com/questions/66002642/caching-python-function-results-using-only-subset-of-arguments-as-identifier) that covers exactly the same question, albeit in Python.

P.S. I am well aware that what my `foo` returns depends on `b`, so it seems odd to memoize it this way, etc. This is just a stupid example that is not meant to be taken seriously.

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [December 11, 2023, 11:04am UTC](https://discourse.julialang.org/t/memoizing-a-function-using-only-a-subset-of-arguments-as-an-identifier/107426/2 "2023-12-11T11:04:57Z")

</div>

I don’t really get the point… If your function output depends only on some inputs (and not further side-effects, which would make Memoization pointless anyways), then why not discard the unused arguments and make it a function of fewer arguments? This also applies to the stackoverflow thread you linked.

I feel like this is a [X-Y question](https://xyproblem.info/) and the true problem sits elsewhere and should be fixed there. Can you perhaps provide a bit more context?

---

<div class="post-metadata">

### Author: ![Aleksandr\_Mikheev](https://avatars.discourse-cdn.com/v4/letter/a/b4bc9f/32.png) [@Aleksandr\_Mikheev](https://discourse.julialang.org/u/Aleksandr_Mikheev)
#### Post date: [December 11, 2023, 11:41am UTC](https://discourse.julialang.org/t/memoizing-a-function-using-only-a-subset-of-arguments-as-an-identifier/107426/3 "2023-12-11T11:41:00Z")

</div>

Yes, I’ve already thought that it might help to give some context.

I am solving a differential equation (well, an integro-differential equation) in which the right-hand side is a functional of the unknown variable itself. For simplicity, let’s say it’s your usual memory integral:

\dot{u}(t) = -u(t) - \int\_0^t dt' u(t')\,.

Using `DifferentialEquations.jl` I can define the right-hand side as

```julia
function f!(du,u,p,t)
    du[1] = -u[1] - mint(t,p)
end

```

where `mint(t::Float64,p::Vector{Float64})` is exactly the memory integral in question, with the second argument being the solution up until time `t`:

```julia
using Trapz

# dt is my timestep, dom is the time domain array

function mint(t,usol)
    return trapz(dom[1:Int(round(t/dt))],usol[1:Int(round(t/dt))])
end

```

Now, say I use a fixed-step integrator of order 3. Then, in order to evaluate my solution at time `t`, I would need the values of my memory integral at times `t`, `t-1`, and `t-2`. But the latter two should have been already computed by that point. So if I cached their values, I would not have to repeat the computation.

The problem is that I have to pass a new “solution array” at each timestep, so what will be called at time `t` are `mint(t, sol at t)`, `mint(t-1, sol at t)`, and `mint(t-2, sol at t)`, whereas the computed values are `mint(t-1, sol at t-1)` and `mint(t-2, sol at t-2)`. Obviously, `mint(t-1, sol at t-1) = mint(t-1, sol at t)`, but I need to let the machine know it somehow.

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [December 11, 2023, 12:16pm UTC](https://discourse.julialang.org/t/memoizing-a-function-using-only-a-subset-of-arguments-as-an-identifier/107426/4 "2023-12-11T12:16:20Z")

</div>

Ah okay I see where you are coming from. While one certainly could write some memoization like you proposed, e.g.

```julia
function make_memory_kernel()
  let data = Dict{Float64, Float64}() # maybe choose more clever datastructure here
    function kernel(t, usol)
      get!(data, t) do
        mint(t, usol)
      end
    end
  end
end

```

Another idea would be rewriting your equations in first order by introducing auxiliary variables (like one usually transforms a N’th order ODE to N first order ODEs). In your example call v \equiv \int\_0^t u(s) ds, then you will get the system:

\begin{align} \dot v(t) &= u(t)\\ \dot u(t) &= -u(t) - v(t) \end{align}

That way you don’t need to do any integration yourself and the integrator handles it all for you.
