# How to write a function that outputs the linear combination of other functions?

**URL:** <https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740>\
**Category:** General Usage\
**Created:** [August 1, 2024, 6:32pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740 "2024-08-01T18:32:45Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![marcsgil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcsgil/32/33908_2.png) [@marcsgil](https://discourse.julialang.org/u/marcsgil)\
**Post date:** [August 1, 2024, 6:32pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/1 "2024-08-01T18:32:45Z")

</div>

I have a certain list of functions `fs` and coefficients `cs` with which I would like form a linear combination, e.g., I’d like to obtain the function

```julia
(args...; kwargs...) -> ( cs[1] * f[1](args...; kwargs...) + ... 
                        + cs[n] * f[n](args...; kwargs...) )

```

The attempt

```julia
function linear_combination(fs, coeffs)
    (args...; kwargs...) -> sum(c * f(args...; kwargs...) for (c,f) ∈ zip(coeffs, fs))
end

```

is a partial solution. By runing the example

```julia
f(x) = x
g(x) = x^2

fs = (f, g)
coeffs = (1,1/2)
h = linear_combination(fs, coeffs)
h(1) # 1.5

```

I get the expected answer, but running `@code_warntype h(1)` gives me

```julia
MethodInstance for (::var"#15#18"{var"#15#16#19"{Tuple{typeof(f), typeof(g)}, Tuple{Int64, Float64}}})(::Int64)
  from (::var"#15#18")(args...; kwargs...) @ Main ~/Desktop/DevStructuredLight.jl/test.jl:4
Arguments
  #self#::var"#15#18"{var"#15#16#19"{Tuple{typeof(f), typeof(g)}, Tuple{Int64, Float64}}}
  args::Tuple{Int64}
Body::Any
1 ─ %1 = Core.getfield(#self#, Symbol("#15#16"))::var"#15#16#19"{Tuple{typeof(f), typeof(g)}, Tuple{Int64, Float64}}
│ %2 = Core.NamedTuple()::Core.Const(NamedTuple())
│ %3 = Base.pairs(%2)::Core.Const(Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}())
│ %4 = Core.tuple(%3, #self#)::Tuple{Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, var"#15#18"{var"#15#16#19"{Tuple{typeof(f), typeof(g)}, Tuple{Int64, Float64}}}}
│ %5 = Core._apply_iterate(Base.iterate, %1, %4, args)::Any
└── return %5

```

so `h` is not type stable. Could anyone help me improve this solution? Thanks!

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [August 1, 2024, 6:50pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/2 "2024-08-01T18:50:51Z")

</div>

What about putting coefficients and functions into a new type?

```julia
struct LinearCombinations{C,F}
    c::C
    f::F
end

function (lc::LinearCombinations)(x...; kw...)
    map(lc.c, lc.f) do c, f
        c*f(x...; kw...)
    end |> sum
end

```

```julia
julia> lc = LinearCombinations(coeffs, (f, g))
LinearCombinations{Tuple{Int64, Float64}, Tuple{typeof(f), typeof(g)}}((1, 0.5), (f, g))

julia> @code_typed lc(1)
CodeInfo(
1 ─ %1 = Core.getfield(x, 1)::Int64
│ %2 = Base.getfield(lc, :c)::Tuple{Int64, Float64}
│ %3 = Base.getfield(%2, 1, true)::Int64
│ %4 = Base.mul_int(%3, %1)::Int64
│ %5 = Base.getfield(%2, 2, true)::Float64
│ %6 = Base.mul_int(%1, %1)::Int64
│ %7 = Base.sitofp(Float64, %6)::Float64
│ %8 = Base.mul_float(%5, %7)::Float64
│ %9 = Base.sitofp(Float64, %4)::Float64
│ %10 = Base.add_float(%9, %8)::Float64
└── return %10
) => Float64

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 1, 2024, 6:55pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/3 "2024-08-01T18:55:06Z")

</div>

> [@matthias314](#):
>
> What about putting coefficients and functions into a new type?

No new type needed. You can also get type-stable code with:

```julia
linear_combinations(f, c) = (x...; kw...) -> map(c, f) do c, f
    c*f(x...; kw...)
end |> sum

```

Defining new callable types (“functors”) can be useful for other reasons, of course; see [How are functors useful? - #6 by stevengj](https://discourse.julialang.org/t/how-are-functors-useful/24110/6)

The trick here is that you construct tuples from tuples (`map` has specialized methods for tuples), rather than generators `foo for (c, f) in zip(...)`. I believe `zip` by itself is also type-unstable for heterogeneous tuples, for that matter.

---

<div class="post-metadata">

**Author:** ![marcsgil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcsgil/32/33908_2.png) [@marcsgil](https://discourse.julialang.org/u/marcsgil)\
**Post date:** [August 1, 2024, 8:33pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/4 "2024-08-01T20:33:06Z")

</div>

This version is indeed type stable! But, at least for the example that I gave, it appears to allocate:

```julia
@benchmark h(1)

BenchmarkTools.Trial: 10000 samples with 999 evaluations.
 Range (min … max): 9.966 ns … 201.626 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 13.266 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 13.422 ns ± 6.974 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

           ▁ ▂█▆▃▂▄▃▂                             
  ▁▁▂▂▂▂▅█▇█▄▂▂▁▁▁▁▁▂▂▃▂▂▃▅████████▆▅▅▅▅▅▄▄▃▃▃▃▂▂▂▂▂▂▁▁▁▁▁▁▁▁▁ ▃
  9.97 ns Histogram: frequency by time 16.9 ns <

 Memory estimate: 16 bytes, allocs estimate: 1.

```

Could it be avoided? It also appears slower than the written version `h(x) = x + x^2 / 2`.

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [August 1, 2024, 9:08pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/5 "2024-08-01T21:08:57Z")

</div>

Use a dollar sign:

```julia
julia> @benchmark $h(1)

BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max): 2.679 ns … 18.640 ns ┊ GC (min … max): 0.00% … 0.00%
 Time (median): 2.772 ns ┊ GC (median): 0.00%
 Time (mean ± σ): 2.963 ns ± 0.540 ns ┊ GC (mean ± σ): 0.00% ± 0.00%

  █ █ ▄▁▁▄ ▄▁ ▃ ▄ ▃▁ ▄ ▃▃ ▂
  █▁██████▅██▁█▆▃█▆▁██▁▆█▄▅▃▁▁▃██▁▄▄▃▁▄▁▁▆▆█▇▆▆▆▆▇▆▇█▇▇▆▇▆▇▇ █
  2.68 ns Histogram: log(frequency) by time 4.86 ns <

 Memory estimate: 0 bytes, allocs estimate: 0.

```

---

<div class="post-metadata">

**Author:** ![marcsgil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcsgil/32/33908_2.png) [@marcsgil](https://discourse.julialang.org/u/marcsgil)\
**Post date:** [August 1, 2024, 9:12pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/6 "2024-08-01T21:12:46Z")

</div>

Well, now the allocation goes away, but I never saw one using `$` before the **function** when benchmarking, only before global variables as arguments. What is going on here? 🤔

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [August 1, 2024, 9:15pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/7 "2024-08-01T21:15:22Z")

</div>

The point is that `h` is a global variable that is not a constant. If you write

```julia
const h = linear_combinations(fs, coeffs)

```

then you don’t need the dollar sign. If you define a function via

```julia
h(x) = x + x^2 / 2

```

then `h` is automatically constant.

---

<div class="post-metadata">

**Author:** ![marcsgil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcsgil/32/33908_2.png) [@marcsgil](https://discourse.julialang.org/u/marcsgil)\
**Post date:** [August 1, 2024, 9:21pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/8 "2024-08-01T21:21:00Z")

</div>

> [@matthias314](#):
>
> then `h` is automatically constant.

I don’t get this observation. I can freely redefine `h`, e.g., I could type `h(x) = x` and then `h(x) = x^2` without a problem. It does not seem constant to me. What am I missing?

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [August 1, 2024, 9:24pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/9 "2024-08-01T21:24:07Z")

</div>

You can add or change methods of a function, but it’s still considered the same function. You cannot do something like the following:

```julia
julia> h(x) = x
h (generic function with 1 method)

julia> h = 1
ERROR: invalid redefinition of constant Main.h

```

---

<div class="post-metadata">

**Author:** ![marcsgil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marcsgil/32/33908_2.png) [@marcsgil](https://discourse.julialang.org/u/marcsgil)\
**Post date:** [August 1, 2024, 9:29pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/10 "2024-08-01T21:29:49Z")

</div>

This seems like a strange definition of “sameness” to me, but I get it now, thank you!

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [August 1, 2024, 9:40pm UTC](https://discourse.julialang.org/t/how-to-write-a-function-that-outputs-the-linear-combination-of-other-functions/117740/11 "2024-08-01T21:40:27Z")

</div>

It may become a bit less strange if you think of a function as a special “dictionary” that maps type signatures to methods. With regular dictionaries, you can say `const d = Dict(1 => 2)` and still add new entries to `d` because it’s considered the same dictionary. (This analogy is not perfect.)
