# \[ANN\] Armington.jl Constant Elasticity of Substitution aggregators in Julia

**URL:** <https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824>\
**Category:** Package Announcements\
**Tags:** package, economics\
**Created:** [June 27, 2026, 12:37pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824 "2026-06-27T12:37:09Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [June 27, 2026, 12:37pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/1 "2026-06-27T12:37:09Z")

</div>

Hi all,

Announcing **Armington.jl** , a small package for building and evaluating arbitrarily-nested CES aggregators, trees where each internal node combines its children with a constant elasticity of substitution. See [Constant elasticity of substitution - Wikipedia](https://en.wikipedia.org/wiki/Constant_elasticity_of_substitution).

Design goals:

- **Zero allocations on evaluation.** Tree topology is encoded in the type parameters, so the recursion unrolls at compile time via tuple peeling.
- **AD-friendly.** `T<:Real` throughout, so `ForwardDiff` duals pass through cleanly.

Quick example:

```julia
using Armington

# Two-level Armington: domestic vs. imports (US, EU)
imports = CESNode(4.0, (0.6, 0.4), (CESLeaf(:US), CESLeaf(:EU)); name=:imports)
tree = CESNode(1.5, (0.7, 0.3), (CESLeaf(:dom), imports); name=:total)

leaf_names(tree) # [:dom, :US, :EU]
aggregate(tree, [10, 5, 8]) # CES composite quantity
show_tree(tree) # print nesting structure

total: CESNode(σ=1.5, α=(0.7, 0.3))
  └ dom
  └ imports: CESNode(σ=4.0, α=(0.6, 0.4))
    └ US
    └ EU

```

Repo: [GitHub - molivov/Armington.jl: Constant Elasticity of Substitution aggregators in Julia · GitHub](https://github.com/molivov/Armington.jl)

Feedback is welcome.

Cheers

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 28, 2026, 4:17pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/2 "2026-06-28T16:17:50Z")

</div>

What’s the function of the wrapper type `CESLeaf`? Couldn’t the constructors just take a `Symbol`?

---

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [June 29, 2026, 4:40am UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/3 "2026-06-29T04:40:03Z")

</div>

Just to keep things consistent: objects are either `CESLeaf` or `CESNode`. I guess I could add a method for a tuple of `Symbol`.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 29, 2026, 6:11am UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/4 "2026-06-29T06:11:33Z")

</div>

That sounds like exposing an implementation detail; my impression is that for the user, `CESLeaf` has no purpose, and `CESNode` could be shortened to `CES`, leading to an API not unlike

```julia
imports = CES(4.0, (0.6, 0.4), (:US, :EU); name = :imports)
tree = CES(1.5, (0.7, 0.3), (:dom, imports); name = :total)

```

---

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [June 29, 2026, 12:25pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/5 "2026-06-29T12:25:40Z")

</div>

This looks much cleaner. However, using `Symbol`s instead of `CESLeaf` requires that anonymous leaves are not allowed, and that is something I want to keep.

`CESNode` to `CES` is harmless, though.

---

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [June 30, 2026, 5:20am UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/6 "2026-06-30T05:20:23Z")

</div>

Ok, I managed to clean the API, now your examples work. Thank you for the suggestion.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 30, 2026, 1:29pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/7 "2026-06-30T13:29:18Z")

</div>

Why not use something like `nothing` for anonymous leafs?

---

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [July 1, 2026, 3:13am UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/8 "2026-07-01T03:13:02Z")

</div>

You mean instead of `Symbol()`? I could do that and use `Union{Symbol, Nothing}` as the type of `name`. What would be the gain?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 1, 2026, 3:39pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/9 "2026-07-01T15:39:08Z")

</div>

No, I meant drop the leaf type entirely, use `::Symbol` for named nodes, and `nothing` for anonymous ones.

(Just a thought. I use CES utility in my work so I might end up using your package. I have a [non-homothetic CES](https://github.com/tpapp/NonhomotheticCES.jl) implementation myself.)

---

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [July 2, 2026, 11:09pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/10 "2026-07-02T23:09:26Z")

</div>

I have plans for developing packages for other kinds of utility functions, perhaps we can coordinate to have consistent APIs.

---

<div class="post-metadata">

**Author:** ![MHaensel](https://avatars.discourse-cdn.com/v4/letter/m/47e85d/32.png) [@MHaensel](https://discourse.julialang.org/u/MHaensel)\
**Post date:** [July 3, 2026, 12:19pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/11 "2026-07-03T12:19:50Z")

</div>

First of all, thank you for providing the package. Given the ubiquity of the CES aggregators in economic modelling, I see that a respective package should be useful.

Looking at your package, I feel it would be useful if it could also return the analytical derivatives of the nested aggregators w.r.t. its inputs, given that these appear very often in model FOCs. Since these FOCs tend to have a special structure at least for standard CES aggregators, that should presumably be possible? I understand that one can ForwardDiff the aggregators, but being able to evaluate the derivates directly would seem simpler and more convenient.

---

<div class="post-metadata">

**Author:** ![molivov](https://avatars.discourse-cdn.com/v4/letter/m/e9bcb4/32.png) [@molivov](https://discourse.julialang.org/u/molivov)\
**Post date:** [July 3, 2026, 11:52pm UTC](https://discourse.julialang.org/t/ann-armington-jl-constant-elasticity-of-substitution-aggregators-in-julia/137824/12 "2026-07-03T23:52:35Z")

</div>

Yes, I thought about that as well. To be honest, I thought I would do derivatives with respect to parameters, since I am more interested in estimating those. In any case, I think the easiest way would be to define some rules for an AD engine?
