Changelog:

Current Tasks:
1.  Add "Statistics" extension
    -   mean(m), std(m), var(m), cov(m), cor(m) #Should have special DimsMap operations
        -   cor(m) should produce a regular numeric matrix (no dimensions at all)
2.  hcat(v::AbstractVector{StaticDims}...) should produce a LinmapQuant with u_out = u""
3.  still need to implement vcat
4.  Move factorizations to LinearAlgebra extension
    -   implement a unitful "cholupdate!" and "choldowndate!"
    -   Look at UnitfulLinearAlgebra, and UnitfulTensors for other factorizations
    -   Add performance benchmarks
5.  Condider refacotring "todims" to "tobase"
    -   Base units is a ubiquitous technical term
    -   This is a better description and matches what "ubase" does
    -   "todims" is not exported, so renaming it isn't technically breaking

Backlog:
1.  Add support for logarithmic quantities 
    -   Should be able to convert to log units using (dB(), log(), log10(), log2())
    -   Multiplying a number with Units{D, ExpAffineTrans} should produce a LogQuant{T, D}
    -   Additional registry is not required here, just a new transform and new kind of quantity
    -   A logarithmic unit is a Unit{D, ExpAffineTrans}
        -   (t<:ExpAffineTrans)(x) = exp(x*t.scale + t.offset)
            -   this is because "todims" is how you transform the value to a base units
            -   log(t::ExpAffineTrans) = AffineTransform(scale=t.scale, offset=t.offset)
            -   exp(t::AffineTransform) = ExpAffineTrans(scale=t.scale, offset=t.offset)
    -   LogQuant{T, U} can have SI units or Affine Transforms (no ExpAffineTrans)
        -   log(Quantity{T,D}) produces a LogQuant{T,D}
        -   uconvert(u::Unit{D,ExpAffineTrans}, u::Unit{D,ExpAffineTrans}) produces an AffineTransform
        -   uconvert(u::Unit{D,ExpAffineTrans}, q::LogQuant) also produces a LogQuant{T, U{D,T<:AffineTransform}}
            -   This just applies an affine transform on the value of q
            -   This is done by using log(todims(u))
        -   uconvert(u::Unit{D,ExpAffineTrans}, q::Quantity) produces a LogQuant{T, U{D,T<:AffineTransform}}
            -   This chains an inv(ExpAffineTrans) transform onto a log(q)
        -   logubase produces LogQuant{T, D}
            -   ubase will convert LogQuant{T, D} to Quantity{T, D}
            -   logubase will convert LogQuant{T, U} to LogQuant{T, D}
        -   quantity(lq::LogQuant) converts to Quantity 
        -   logquant(q::Quantity) converts to LogQuant 
    -   Unit{D, ExpAffineTrans} will have a symbol that's generated by a logarithmic constructor 
        -   dB(u"kPa") will have the symbol "dB(kPa)"
        -   dB(101.3u"kPa") will have the symbol "dB(101300 kg/(m s²))"
        -   Symbol will remain if taking "exp" or "log" of the unit
        -   Quantity{T, U{D,<:ExpAffineTrans}} looks the same as LogQuant{T, U{D,<:AffineTransform}}
            -   The difference is behaviour with respect to operators
            -   Quantity{T, U{D,<:ExpAffineTrans}} probably won't exist unless expliticly constructed

2.  Add plot recipes
    -   https://github.com/JuliaPlots/Plots.jl/blob/v2/PlotsBase/ext/UnitfulExt.jl
3.  Add interactive unit functionality
    -   unit_index() (produces dict that lists all units for every dimension)
    -   simplify(q::Quantity{T,AbstractDimLike}) 
        -   Lists all standard SI units, performs a greedy search to make units as terse as possible
            e.g. simplify(1.0u"(m^2*kg)/s^3") = 1 kW
        -   Only works if all unit powers are integers


#Example of #3 is shown below

julia> using FlexUnits, .UnitRegistry

julia> (x, y, z) = 1u"m/s", 1u"kg", 1u"kW"
(1.0 m/s, 1.0 kg, 1000.0 (m² kg)/s³)

julia> T = Union{typeof(x),typeof(y), typeof(z)}
Union{Quantity{Float64, StaticDims{m/s}}, Quantity{Float64, StaticDims{kg}}, Quantity{Float64, StaticDims{(m² kg)/s³}}}

julia> v = T[x,y,z]
3-element Vector{Union{Quantity{Float64, StaticDims{m/s}}, Quantity{Float64, StaticDims{kg}}, Quantity{Float64, StaticDims{(m² kg)/s³}}}}:
 1.0 m/s
 1.0 kg
 1000.0 (m² kg)/s³

julia> map(x->x*2, v)
3-element Vector{Quantity{Float64}}:
 2.0 m/s
 2.0 kg
 2000.0 (m² kg)/s³

julia> map(x->x*2, [x,y,z])
3-element Vector{Quantity{Float64, Dimensions{FixRat32}}}:
 2.0 m/s
 2.0 kg
 2000.0 (m² kg)/s³

julia> collect(map(x->x*2, (x,y,z)))
3-element Vector{Quantity{Float64}}:
 2.0 m/s
 2.0 kg
 2000.0 (m² kg)/s³

julia> vcat((map(x->x*2, (x,y,z)))...)
3-element Vector{Quantity{Float64, Dimensions{FixRat32}}}:
 2.0 m/s
 2.0 kg
 2000.0 (m² kg)/s³





#====================================================================================================
Some benchmarks
====================================================================================================#
import DynamicQuantities
import Unitful
using BenchmarkTools

v1flex = ubase.([1u"m/s", 1u"J/kg", 1u"A/V"])
v1uni  = [1*Unitful.u"m/s", 1*Unitful.u"J/kg", 1*Unitful.u"A/V"]
v1dyn  = [1*DynamicQuantities.u"m/s", 1*DynamicQuantities.u"J/kg", 1*DynamicQuantities.u"A/V"]

@btime sum(x->x^0.0, v1uni)
@btime sum(x->x^0.0, v1flex)
@btime sum(x->x^0.0, v1dyn)

t1flex = ubase.((1u"m/s", 1u"J/kg", 1u"A/V"))
t1uni  = (1*Unitful.u"m/s", 1*Unitful.u"J/kg", 1*Unitful.u"A/V")
t1dyn  = (1*DynamicQuantities.u"m/s", 1*DynamicQuantities.u"J/kg", 1*DynamicQuantities.u"A/V")

@btime sum(x->x^0, t1uni)
@btime sum(x->x^0, t1flex)
@btime sum(x->x^0, t1dyn)


