-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from GiggleLiu/ulog
logarithmic number system
- Loading branch information
Showing
19 changed files
with
373 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
""" | ||
## Reference | ||
[1] C. S. Turner, "A Fast Binary Logarithm Algorithm", IEEE Signal | ||
Processing Mag., pp. 124,140, Sep. 2010. | ||
""" | ||
function log2fix(x::Fixed{T, P}) where {T, P} | ||
PREC = UInt(P) | ||
x.i == 0 && return typemin(T) # represents negative infinity | ||
|
||
y = zero(T) | ||
xi = unsigned(x.i) | ||
while xi < UInt(1) << PREC | ||
xi <<= UInt(1) | ||
y -= 1 << PREC | ||
end | ||
|
||
while xi >= UInt(2) << PREC | ||
xi >>= UInt(1) | ||
y += 1 << PREC | ||
end | ||
|
||
z = Int128(xi) | ||
b = 1 << (PREC - UInt(1)) | ||
for i = 1:P | ||
z = (z * z) >> PREC | ||
if z >= 2 << PREC | ||
z >>= UInt(1) | ||
y += b | ||
end | ||
b >>= UInt(1) | ||
end | ||
|
||
return Fixed{T,PREC}(y, nothing) | ||
end | ||
|
||
@test log2fix(Fixed43(2^1.24)) ≈ 1.24 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# # Logarithmic number system | ||
|
||
# Computing basic functions like `power`, `exp` and `besselj` is not trivial for reversible programming. | ||
# There is no efficient constant memory algorithm using pure fixed point numbers only. | ||
# For example, to compute `x ^ n` reversiblly with fixed point numbers, | ||
# we need to allocate a vector of size $O(n)$. | ||
# With logarithmic numbers, the above computation is straight forward. | ||
|
||
using LogarithmicNumbers | ||
using NiLang, NiLang.AD | ||
using FixedPointNumbers | ||
|
||
@i function i_power(y::T, x::T, n::Int) where T | ||
@routine begin | ||
lx ← one(ULogarithmic{T}) | ||
ly ← one(ULogarithmic{T}) | ||
## convert `x` to a logarithmic number | ||
## Here, `*=` is reversible for log numbers | ||
lx *= convert(x) | ||
for i=1:n | ||
ly *= lx | ||
end | ||
end | ||
|
||
## convert back to fixed point numbers | ||
y += convert(ly) | ||
|
||
~@routine | ||
end | ||
|
||
# To check the function | ||
i_power(Fixed43(0.0), Fixed43(0.4), 3) | ||
|
||
# ## `exp` function as an example | ||
# The following example computes `exp(x)`. | ||
|
||
@i function i_exp(y!::T, x::T) where T<:Union{Fixed, GVar{<:Fixed}} | ||
@invcheckoff begin | ||
@routine begin | ||
s ← one(ULogarithmic{T}) | ||
lx ← one(ULogarithmic{T}) | ||
k ← 0 | ||
end | ||
lx *= convert(x) | ||
y! += convert(s) | ||
while (s.log > -20, k != 0) | ||
k += 1 | ||
s *= lx / k | ||
y! += convert(s) | ||
end | ||
~(while (s.log > -20, k != 0) | ||
k += 1 | ||
s *= x / k | ||
end) | ||
lx /= convert(x) | ||
~@routine | ||
end | ||
end | ||
|
||
x = Fixed43(3.5) | ||
|
||
# We can check the reversibility | ||
out, _ = i_exp(Fixed43(0.0), x) | ||
@assert out ≈ exp(3.5) | ||
|
||
# Computing the gradients | ||
_, gx = NiLang.AD.gradient(Val(1), i_exp, (Fixed43(0.0), x)) | ||
@assert gx ≈ exp(3.5) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
@i function (:-=)(gaussian_log)(y!::GVar{T}, x::GVar{T}) where T | ||
y!.x -= gaussian_log(x.x) | ||
@routine @invcheckoff begin | ||
exp_x ← zero(x) | ||
jac ← zero(x) | ||
exp_x += exp(-x) | ||
exp_x += 1 | ||
jac += 1/exp_x | ||
end | ||
x.g += y!.g * jac | ||
~@routine | ||
end | ||
|
||
@i function (:-=)(gaussian_nlog)(y!::GVar{T}, x::GVar{T}) where T | ||
y!.x -= gaussian_nlog(x.x) | ||
@routine @invcheckoff begin | ||
exp_x ← zero(x) | ||
jac ← zero(x) | ||
exp_x += exp(-x) | ||
exp_x -= 1 | ||
jac -= 1/exp_x | ||
end | ||
x.g += y!.g * jac | ||
~@routine | ||
end | ||
|
||
@i function :(-=)(convert)(out!::GVar{Tx, Tg}, y::ULogarithmic) where {Tx, Tg} | ||
out! -= exp(y.log) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using LogarithmicNumbers | ||
export gaussian_log, gaussian_nlog | ||
export ULogarithmic | ||
|
||
function NiLangCore.default_constructor(ln::Type{<:ULogarithmic}, x) | ||
exp(ULogarithmic, x) | ||
end | ||
|
||
@i @inline function (:*=(identity))(x::T, y::T) where T<:ULogarithmic | ||
x.log += y.log | ||
end | ||
|
||
for (OP1, OP2, OP3) in [(:*, :+, :(+=)), (:/, :-, :(-=))] | ||
@eval @i @inline function (:*=($OP1))(out!::T, x::T, y::T) where T<:ULogarithmic | ||
out!.log += $OP2(x.log, y.log) | ||
end | ||
|
||
@eval @i @inline function (:*=($OP1))(out!::T, x::Real, y::Real) where T<:ULogarithmic | ||
out!.log += log(x) | ||
$(Expr(OP3, :(out!.log), :(log(y)))) | ||
end | ||
|
||
@eval @i @inline function (:*=($OP1))(out!::T, x::T, y::Real) where T<:ULogarithmic | ||
out!.log += x.log | ||
$(Expr(OP3, :(out!.log), :(log(y)))) | ||
end | ||
|
||
@eval @i @inline function (:*=($OP1))(out!::T, x::Real, y::T) where T<:ULogarithmic | ||
out!.log += log(x) | ||
$(Expr(OP3, :(out!.log), :(y.log))) | ||
end | ||
end | ||
|
||
gaussian_log(x) = log1p(exp(x)) | ||
gaussian_nlog(x) = log1p(-exp(x)) | ||
|
||
@i function (:*=)(+)(out!::ULogarithmic{T}, x::ULogarithmic{T}, y::ULogarithmic{T}) where {T} | ||
@invcheckoff if (x.log == y.log, ~) | ||
out!.log += x.log | ||
out!.log += log(2) | ||
elseif (x.log ≥ y.log, ~) | ||
out!.log += x.log | ||
y.log -= x.log | ||
out!.log += gaussian_log(y.log) | ||
y.log += x.log | ||
else | ||
out!.log += y.log | ||
x.log -= y.log | ||
out!.log += gaussian_log(x.log) | ||
x.log += y.log | ||
end | ||
end | ||
|
||
@i function (:*=)(-)(out!::ULogarithmic{T}, x::ULogarithmic{T}, y::ULogarithmic{T}) where {T} | ||
@safe @assert x.log ≥ y.log | ||
@invcheckoff if (!iszero(x), ~) | ||
out!.log += x.log | ||
y.log -= x.log | ||
out!.log += gaussian_nlog(y.log) | ||
y.log += x.log | ||
end | ||
end | ||
|
||
@i function :(*=)(convert)(out!::ULogarithmic{T}, y::ULogarithmic) where T | ||
out!.log += convert((@skip! T), y.log) | ||
end | ||
|
||
@i function :(*=)(convert)(out!::ULogarithmic{T}, y::T) where T<:Real | ||
out!.log += log(y) | ||
end | ||
|
||
Base.convert(::Type{T}, x::ULogarithmic{T}) where {T<:Fixed} = exp(x.log) | ||
|
||
function NiLangCore.deanc(x::T, v::T) where T<:ULogarithmic | ||
x === v || NiLangCore.deanc(x.log, v.log) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.