# \[ANN\] AffineMaps.jl

**URL:** <https://discourse.julialang.org/t/ann-affinemaps-jl/100751>\
**Category:** Community\
**Created:** [June 23, 2023, 5:44pm UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751 "2023-06-23T17:44:42Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [June 23, 2023, 5:44pm UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/1 "2023-06-23T17:44:42Z")

</div>

Just wanted to announce [AffineMaps](https://github.com/oschulz/AffineMaps.jl).

AffineMaps is a very lightweight package to express affine transforms (A \* x + b, and variants). It provides function objects for add, mul, muladd and addmul. These support [`InverseFunctions.inverse`](https://github.com/JuliaMath/InverseFunctions.jl) as well as [`ChangesOfVariables.logabsdetjacobian`](https://github.com/JuliaMath/ChangesOfVariables.jl) and the [Functors](https://github.com/FluxML/Functors.jl) API.

Example:

```julia
using AffineMaps
using LinearAlgebra, InverseFunctions, ChangesOfVariables
A = rand(5, 5)
b = rand(5)
x = rand(5)

f = MulAdd(A, b)
y = f(x)
y ≈ A * x + b

inverse(f)(y) ≈ x

y, ladj = with_logabsdet_jacobian(f, x)
y ≈ A * x + b && ladj ≈ logabsdet(A)[1]

```

We have similar functionality in many packages of course, AffineMaps is mainly about offering this as very lightweight dependency.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 25, 2023, 3:28pm UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/2 "2023-06-25T15:28:31Z")

</div>

Does/can it provide traits like `islinear(f)` and `isaffine(f)` for arbitrary functions?  
These are occasionally useful, eg [in FlexiMaps](https://gitlab.com/aplavin/FlexiMaps.jl/-/blob/master/src/mapview.jl#L143-153) to determine when `mapview(f, range)` can return a range vs array.

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [June 25, 2023, 7:30pm UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/3 "2023-06-25T19:30:37Z")

</div>

Oh, I wasn’t aware of FlexiMaps (nice package!) but I’m happy to support it via an AffineMaps Pkg extension. Are `islinear` and `isaffine` originally defined in FlexiMaps, or are they owned by another package?

I can also add `islinear` and `isaffine` propagation to [FunctionChains](https://github.com/oschulz/FunctionChains.jl) (need to properly announce that package sometime 🙂 ).

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [June 26, 2023, 1:44am UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/4 "2023-06-26T01:44:10Z")

</div>

@aplavin AffineMaps and FunctionChains support FlexiMaps.islinear and FlexiMaps.isaffine now. 🙂

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [June 26, 2023, 8:24am UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/5 "2023-06-26T08:24:17Z")

</div>

Great!  
I was also looking for a more natural way to put those `islinear`/`isaffine` traits, `FlexiMaps` seems very adhoc for this…

---

<div class="post-metadata">

**Author:** ![evetion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/evetion/32/22679_2.png) [@evetion](https://discourse.julialang.org/u/evetion)\
**Post date:** [August 11, 2023, 12:33pm UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/6 "2023-08-11T12:33:17Z")

</div>

Can you comment on how the packages compares with the AffineMap from [CoordinateTransformations.jl](https://github.com/JuliaGeometry/CoordinateTransformations.jl)?

---

<div class="post-metadata">

**Author:** ![oschulz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oschulz/32/2998_2.png) [@oschulz](https://discourse.julialang.org/u/oschulz)\
**Post date:** [August 11, 2023, 2:29pm UTC](https://discourse.julialang.org/t/ann-affinemaps-jl/100751/7 "2023-08-11T14:29:26Z")

</div>

> @evetion: Can you comment on how the packages compares with the AffineMap from CoordinateTransformations.jl?

I would say it’s more fully featured, regarding to the affine maps itself - AffineMaps offers both rotate-then-translate (`MulAdd`) and translate-then-rotate (`AddMul`), it also supports InverseFunctions, ChangesOfVariables, FlexiMaps and Functors (so it cal also be used as ML layers). On the other hand the scope of CoordinateTransformations as a whole is wider, and there’s probably also some things in `CoordinateTransformations.AffineMap` that AffineMaps.jl lacks.

Ideally, one could see if AffineMaps.jl does lack anything that CoordinateTransformations.jl needs (which is likely), add it, and then have CoordinateTransformations.jl depend on AffineMaps.jl and get it’s maps from there. The problem is that `CoordinateTransformations.AffineMap` is a subtype of `CoordinateTransformations.Transformation`, so that won’t work. We’d need a AbstractCoordinateTransformations.jl package or so …

Currently CoordinateTransformations is also a much heavier dependency than AffineMaps, due to StaticArrays, but I think CoordinateTransformations could move the StaticArrays code into a Pkg extension. CoordinateTransformations itself shouldn’t be that heavy.

There’s also some discussion here: [Comparison to CoordinateTransformations.jl? · Issue #1 · oschulz/AffineMaps.jl · GitHub](https://github.com/oschulz/AffineMaps.jl/issues/1)
