diff --git a/Project.toml b/Project.toml index d29980d..fdd875c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "NiLang" uuid = "ab4ef3a6-0b42-11ea-31f6-e34652774712" authors = ["JinGuo Liu", "thautwarm"] -version = "0.8.5" +version = "0.9.0" [deps] FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" @@ -10,6 +10,7 @@ LogarithmicNumbers = "aa2f6b4e-9042-5d33-9679-40d3a6b85899" MatchCore = "5dd3f0b1-72a9-48ad-ae6e-79f673da005f" NiLangCore = "575d3204-02a4-11ea-3f62-238caa8bf11e" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" +Requires = "ae029012-a4dd-5104-9daa-d747884805df" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" TupleTools = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6" @@ -17,7 +18,7 @@ TupleTools = "9d95972d-f1c8-5527-a6e0-b4b365fa01f6" FixedPointNumbers = "0.6, 0.7, 0.8" LogarithmicNumbers = "0.4" MatchCore = "0.1" -NiLangCore = "0.9.1" +NiLangCore = "0.10.1" Reexport = "0.2, 1.0" TupleTools = "1.2" julia = "1.3" diff --git a/benchmark/stack.jl b/benchmark/stack.jl new file mode 100644 index 0000000..e69de29 diff --git a/examples/fft.jl b/examples/fft.jl index 86e43e0..b5e1745 100644 --- a/examples/fft.jl +++ b/examples/fft.jl @@ -32,7 +32,7 @@ end using NiLang @i function i_fft!(x::AbstractVector{T}) where T - @invcheckoff N ← length(x) + @routine @invcheckoff N ← length(x) @safe @assert N%2 == 0 @invcheckoff @inbounds if N <= 1 elseif N == 2 @@ -57,12 +57,15 @@ using NiLang end # combine for i=1:N÷2 - θ ← -2*π*(i-1)/N + @routine θ ← -2*π*(i-1)/N ROT(x[i+N÷2].re, x[i+N÷2].im, θ) HADAMARD(x[i].re, x[i+N÷2].re) HADAMARD(x[i].im, x[i+N÷2].im) + ~@routine end + x2 → zeros(T, N) end + ~@routine end using Test, FFTW diff --git a/examples/fib.jl b/examples/fib.jl index 82cd818..fa2abfd 100644 --- a/examples/fib.jl +++ b/examples/fib.jl @@ -3,9 +3,9 @@ using NiLang @i function rfib(out!, n::T) where T - n1 ← zero(T) - n2 ← zero(T) @routine begin + n1 ← zero(T) + n2 ← zero(T) n1 += n - 1 n2 += n - 2 end @@ -31,6 +31,7 @@ end rfib(out, n!) end ~rfib(out, n!) + out → 0 end # In this example, the postcondition `n!=0` in the `while` statement is false before entering the loop, and it becomes true in later iterations. In the reverse program, the `while` statement stops at `n==0`. diff --git a/examples/lax_wendroff.jl b/examples/lax_wendroff.jl index 77fb854..8f20c67 100644 --- a/examples/lax_wendroff.jl +++ b/examples/lax_wendroff.jl @@ -62,6 +62,7 @@ using NiLang cache[nx+1,j] += q[2] SWAP(q[nx], cache[nx+1,j]) end + nx → length(q) end nt = 2000 i_lax_wendroff!(nt, 1.0, q_init, zero(q_init), zeros(length(q_init)+1,nt)) diff --git a/examples/nice.jl b/examples/nice.jl index 0341a3f..ff36261 100644 --- a/examples/nice.jl +++ b/examples/nice.jl @@ -58,6 +58,7 @@ const NiceNetwork{T} = Vector{NiceLayer{T}} else @inbounds nice_layer!(x! |> subarray(1:np÷2), network[i], x! |> subarray(np÷2+1:np)) end + np → length(x!) end end diff --git a/examples/qr.jl b/examples/qr.jl index 7c9d184..0050ffe 100644 --- a/examples/qr.jl +++ b/examples/qr.jl @@ -2,16 +2,18 @@ # ## Functions used in this example -using NiLang, NiLang.AD +using NiLang, NiLang.AD, Test # ## The QR decomposition # Let us consider a naive implementation of QR decomposition from scratch. # This implementation is just a proof of principle which does not consider reorthogonalization and other practical issues. @i function qr(Q, R, A::Matrix{T}) where T - anc_norm ← zero(T) - anc_dot ← zeros(T, size(A,2)) - ri ← zeros(T, size(A,1)) + @routine begin + anc_norm ← zero(T) + anc_dot ← zeros(T, size(A,2)) + ri ← zeros(T, size(A,1)) + end for col = 1:size(A, 1) ri .+= A[:,col] for precol = 1:col-1 @@ -41,6 +43,7 @@ using NiLang, NiLang.AD i_norm2(anc_norm, ri) end end + ~@routine end # Here, in order to avoid frequent uncomputing, we allocate ancillas `ri` and `anc_dot` as vectors. @@ -55,7 +58,7 @@ q, r = zero(A), zero(A) i_sum(out, q) end -check_grad(test1, (0.0, q, r, A); iloss=1) +@test check_grad(test1, (0.0, q, r, A); iloss=1) # Here, the loss function `test1` is defined as the sum of the output unitary matrix `q`. # The `check_grad` function is a gradient checker function defined in module `NiLang.AD`. diff --git a/src/NiLang.jl b/src/NiLang.jl index fe8fe6a..a6d4c4f 100644 --- a/src/NiLang.jl +++ b/src/NiLang.jl @@ -5,6 +5,7 @@ using Reexport import NiLangCore: invtype using FixedPointNumbers: Q20f43, Fixed +import NiLangCore: empty_global_stacks!, loaddata export Fixed43 const Fixed43 = Q20f43 @@ -13,7 +14,6 @@ include("wrappers.jl") include("vars.jl") include("instructs.jl") include("ulog.jl") -include("stack.jl") include("complex.jl") include("autobcast.jl") include("macros.jl") diff --git a/src/autodiff/autodiff.jl b/src/autodiff/autodiff.jl index 5516151..e2f3048 100644 --- a/src/autodiff/autodiff.jl +++ b/src/autodiff/autodiff.jl @@ -5,13 +5,14 @@ using NiLangCore using MatchCore, TupleTools import ..NiLang: ROT, IROT, SWAP, - chfield, value, NoGrad, loaddata, INC, DEC, HADAMARD, + chfield, value, NoGrad, INC, DEC, HADAMARD, AddConst, SubConst, NEG, INV using NiLangCore: default_constructor export GVar, grad, Loss, NoGrad, @nograd include("vars.jl") +include("stack.jl") include("gradfunc.jl") include("checks.jl") diff --git a/src/autodiff/stack.jl b/src/autodiff/stack.jl new file mode 100644 index 0000000..2323971 --- /dev/null +++ b/src/autodiff/stack.jl @@ -0,0 +1,15 @@ +# This is a patch for loading a data to GVar correctly. +import NiLangCore + +NiLangCore.loaddata(::Type{GT}, x::T) where {T, GT<:GVar{T}} = convert(GT, x) +function NiLangCore.loaddata(t::Type{VT}, x::AbstractVector) where {T, VT<:AbstractVector{T}} + convert.(T, x) +end + +function NiLangCore.loaddata(t::VT, x::AbstractVector) where {T, VT<:AbstractVector{T}} + convert(VT, NiLangCore.loaddata.(t, x)) +end + +function NiLangCore.loaddata(::Type{T}, x::XT) where {N, T<:Tuple{N}, XT<:Tuple{N}} + ntuple(i=>NiLangCore.loaddata.(T.parameters[i], [i]), N) +end diff --git a/src/autodiff/vars.jl b/src/autodiff/vars.jl index 8e43556..5caa7da 100644 --- a/src/autodiff/vars.jl +++ b/src/autodiff/vars.jl @@ -128,7 +128,7 @@ chfield(x::GVar, ::typeof(grad), g::GVar) = GVar(x.x, g) chfield(x::Complex{<:GVar}, ::typeof(grad), g::Complex) = Complex(GVar(value(x.re), g.re), GVar(value(x.im), g.im)) # NOTE: superwarning: check value only to make ancilla gradient descardable. -NiLangCore.deanc(x::GVar, val::GVar) = NiLangCore.deanc(value(x), value(val)) +NiLangCore.deanc(x::GVar{T}, val::GVar{T}) where T = NiLangCore.deanc(value(x), value(val)) function deanc(x::T, val::T) where {T<:AbstractArray} x === val || deanc.(x, val) end @@ -186,19 +186,6 @@ macro nograd(ex) end end -# load data from stack -function loaddata(::Type{TG}, x::T) where {T,TG<:GVar{T}} - TG(x) -end - -function loaddata(::Type{T}, x::T) where T <: GVar - x -end - -function loaddata(::Type{AGT}, x::AT) where {T, GT, AT<:AbstractArray{T}, AGT<:AbstractArray{GVar{T,T}}} - map(x->GVar(x, zero(x)), x) -end - # ULogarithmic _content(x::ULogarithmic) = x.log NiLang.AD.GVar(x::ULogarithmic) = exp(ULogarithmic, GVar(_content(x), zero(_content(x)))) @@ -209,10 +196,6 @@ Base.one(::Type{ULogarithmic{GVar{T,GT}}}) where {T,GT} = exp(ULogarithmic, GVar Base.zero(x::ULogarithmic{GVar{T,GT}}) where {T,GT} =zero(ULogarithmic{GVar{T,GT}}) Base.zero(::Type{ULogarithmic{GVar{T,T}}}) where T = exp(ULogarithmic, GVar(zero(T), zero(T))) -function NiLang.loaddata(::Type{Array{<:ULogarithmic{GVar{T,T}}}}, data::Array{<:ULogarithmic{T}}) where {T} - GVar.(data) -end - # the patch for dicts function GVar(d::Dict) Dict([(k=>GVar(v)) for (k, v) in d]) diff --git a/src/instructs.jl b/src/instructs.jl index c6174e7..a0ff425 100644 --- a/src/instructs.jl +++ b/src/instructs.jl @@ -2,6 +2,7 @@ export SWAP, FLIP export ROT, IROT export INC, DEC, NEG, INV, AddConst, SubConst export HADAMARD +export PUSH!, POP!, COPYPOP!, COPYPUSH! """ NoGrad{T} <: IWrapper{T} @@ -180,3 +181,39 @@ Base.:~(ac::SubConst) = AddConst(ac.x) for F in [:INV, :NEG, :FLIP, :INC, :DEC] @eval NiLangCore.chfield(x::T, ::typeof($F), xval::T) where T<:Real = (~$F)(xval) end + +#### The following functions are not safe! +@i @inline function PUSH!(x::T) where T + PUSH!((@skip! GLOBAL_STACK), x) +end + +@i @inline function POP!(x::T) where T + POP!((@skip! GLOBAL_STACK), x) +end + +@i @inline function COPYPUSH!(x) + COPYPUSH!((@skip! GLOBAL_STACK), x) +end + +@i @inline function COPYPOP!(x) + COPYPOP!((@skip! GLOBAL_STACK), x) +end + +# reversibility turned off, in principle, we can not deallocate `GVar{T}` to `T` +@i @inline function PUSH!(st, x::T) where T + @invcheckoff st[end+1] ↔ x + @invcheckoff x ← _zero(T) +end + +@i @inline function POP!(st, x::T) where T + @invcheckoff x → _zero(T) + @invcheckoff st[end] ↔ (x::T)::∅ +end + +@i @inline function COPYPUSH!(st, x) + @invcheckoff st[end+1] ← x +end + +@i @inline function COPYPOP!(st, x) + @invcheckoff st[end] → x +end \ No newline at end of file diff --git a/src/stack.jl b/src/stack.jl deleted file mode 100644 index 886535e..0000000 --- a/src/stack.jl +++ /dev/null @@ -1,78 +0,0 @@ -export POP!, PUSH!, COPYPUSH!, COPYPOP!, GLOBAL_STACK - -const GLOBAL_STACK = [] - -############# global stack operations ########## -@inline function PUSH!(x) - push!(GLOBAL_STACK, x) - _zero(x) -end - -@inline function POP!(x::T) where T - NiLangCore.deanc(x, _zero(x)) - loaddata(T, pop!(GLOBAL_STACK)) -end - -UNSAFE_PUSH!(args...) = PUSH!(args...) -@inline function UNSAFE_POP!(x::T) where T - loaddata(T, pop!(GLOBAL_STACK)) -end - -############# local stack operations ########## -@inline function PUSH!(stack, x::T) where T - push!(stack, x) - stack, _zero(T) -end - -@inline function POP!(stack, x::T) where T - NiLangCore.deanc(x, _zero(T)) - stack, loaddata(T, pop!(stack)) -end - -@inline function UNSAFE_POP!(stack, x::T) where T - stack, loaddata(T, pop!(stack)) -end - -loaddata(::Type{T}, x::T) where T = x - -@dual POP! PUSH! -@dual UNSAFE_POP! UNSAFE_PUSH! - -############# copied push/pop stack operations ########## -@inline function COPYPUSH!(stack, x) - push!(stack, copy(x)) - stack, x -end - -@inline function COPYPOP!(stack, x) - y = pop!(stack) - NiLangCore.deanc(x, y) - stack, y -end - -UNSAFE_COPYPUSH!(args...) = COPYPUSH!(args...) -@inline function UNSAFE_COPYPOP!(stack, x::XT) where XT - y = pop!(stack) - stack, convert(XT, y) -end - -@inline function COPYPUSH!(x) - push!(GLOBAL_STACK, x) - x -end - -@inline function COPYPOP!(x::XT) where XT - y = pop!(GLOBAL_STACK) - NiLangCore.deanc(x, y) - convert(XT, y) -end - -@inline function UNSAFE_COPYPOP!(x) - y = pop!(GLOBAL_STACK) - y -end - -@dual COPYPOP! COPYPUSH! -@dual UNSAFE_COPYPOP! UNSAFE_COPYPUSH! - -loaddata(::Type{T}, x::TX) where {T<:NullType, TX} = T(x) diff --git a/src/stdlib/blas.jl b/src/stdlib/blas.jl index 6666704..11a81bf 100644 --- a/src/stdlib/blas.jl +++ b/src/stdlib/blas.jl @@ -36,12 +36,14 @@ end @i function i_mul!(out!::AbstractVector{T}, x::AbstractMatrix, y::AbstractVector) where T @safe size(x, 2) == size(y, 1) || throw(DimensionMismatch()) @invcheckoff @inbounds for j=1:size(x,2) - yj ← zero(T) - yj += y[j] + @routine begin + yj ← zero(T) + yj += y[j] + end for i=1:size(x,1) out![i] += x[i,j] * yj end - yj -= y[j] + ~@routine end end @@ -81,8 +83,10 @@ end Compute unitary matrix multiplication on `x`, where the unitary matrix is parameterized by (N+1)*N/2 `θ`s. """ @i function i_umm!(x!::AbstractArray, θ) - M ← size(x!, 1) - N ← size(x!, 2) + @routine begin + M ← size(x!, 1) + N ← size(x!, 2) + end k ← 0 @safe @assert length(θ) == M*(M-1)/2 for l = 1:N @@ -95,4 +99,5 @@ Compute unitary matrix multiplication on `x`, where the unitary matrix is parame end k → length(θ) + ~@routine end diff --git a/src/stdlib/mapreduce.jl b/src/stdlib/mapreduce.jl index d77a8e3..5f20c07 100644 --- a/src/stdlib/mapreduce.jl +++ b/src/stdlib/mapreduce.jl @@ -12,6 +12,7 @@ Reversible `mapfoldl` function, `map` can be irreversible, but `fold` should be fold(out!, anc) anc -= map(iter[i]) end + anc → zero(T) end """ diff --git a/src/stdlib/nnlib.jl b/src/stdlib/nnlib.jl index 1be52e3..410d8c8 100644 --- a/src/stdlib/nnlib.jl +++ b/src/stdlib/nnlib.jl @@ -17,8 +17,6 @@ end Softmax-Cross entropy function. """ @i function i_softmax_crossentropy(x, p, imax, xmax, Z, out::T) where T - logZ ← zero(T) - yi ← zero(T) # subtract maximum imax += argmax(x) # trade off space of xmax to time xmax += x[imax] @@ -27,7 +25,11 @@ Softmax-Cross entropy function. x[i] -= xmax Z += Base.exp(x[i]) end - logZ += log(Z) + @routine begin + yi ← zero(T) + logZ ← zero(T) + logZ += log(Z) + end for i=1:length(x) yi += logZ yi -= x[i] @@ -35,7 +37,7 @@ Softmax-Cross entropy function. yi += x[i] yi -= logZ end - logZ -= log(Z) + ~@routine end """ @@ -63,9 +65,11 @@ Compute `logout! = log(sum(exp(x)))`. * `x`, input vector. """ @i function i_logsumexp(logout!, out!, xs!, inds!, x::AbstractArray{T}) where T - mx ← zero(T) i_ascending!(xs!, inds!, x) - mx += xs![end] + @routine begin + mx ← zero(T) + mx += xs![end] + end @invcheckoff @inbounds for i=1:length(x) x[i] -= mx out! += exp(x[i]) @@ -73,7 +77,7 @@ Compute `logout! = log(sum(exp(x)))`. end logout! += log(out!) logout! += mx - mx -= xs![end] + ~@routine end diff --git a/src/stdlib/sorting.jl b/src/stdlib/sorting.jl index af04adb..6102249 100644 --- a/src/stdlib/sorting.jl +++ b/src/stdlib/sorting.jl @@ -10,18 +10,16 @@ This function can be used to get the maximum value and maximum indices. @invcheckoff if (length(arr) > 0, ~) y ← zero(T) y += arr[1] - PUSH!(xs!, y) + xs![end+1] ↔ y anc ← 1 - PUSH!(inds!, anc) - anc → 0 + inds![end+1] ↔ anc @inbounds for i = 2:length(arr) if (arr[i] > xs![end], i==inds![end]) ind ← i x ← zero(T) x += arr[i] - PUSH!(xs!, x) - PUSH!(inds!, ind) - ind → 0 + xs![end+1] ↔ x + inds![end+1] ↔ ind end end end diff --git a/src/stdlib/sparse.jl b/src/stdlib/sparse.jl index b0e0d82..83c4078 100644 --- a/src/stdlib/sparse.jl +++ b/src/stdlib/sparse.jl @@ -4,37 +4,45 @@ using SparseArrays @safe size(A, 2) == size(B, 1) || throw(DimensionMismatch()) @safe size(A, 1) == size(C, 1) || throw(DimensionMismatch()) @safe size(B, 2) == size(C, 2) || throw(DimensionMismatch()) - nzv ← nonzeros(A) - rv ← rowvals(A) + @routine begin + nzv ← nonzeros(A) + rv ← rowvals(A) + end if (β != 1, ~) @safe error("only β = 1 is supported, got β = $(β).") end # Here, we close the reversibility check inside the loop to increase performance @invcheckoff for k = 1:size(C, 2) @inbounds for col = 1:size(A, 2) - αxj ← zero(T) - αxj += B[col,k] * α + @routine begin + αxj ← zero(T) + αxj += B[col,k] * α + end for j = SparseArrays.getcolptr(A)[col]:(SparseArrays.getcolptr(A)[col + 1] - 1) C[rv[j], k] += nzv[j]*αxj end - αxj -= B[col,k] * α + ~@routine end end + ~@routine end @i function i_dot(r::T, A::SparseMatrixCSC{T},B::SparseMatrixCSC{T}) where {T} - m ← size(A, 1) - n ← size(A, 2) - @invcheckoff branch_keeper ← zeros(Bool, 2*m) + @routine @invcheckoff begin + (m, n) ← size(A) + branch_keeper ← zeros(Bool, 2*m) + end @safe size(B) == (m,n) || throw(DimensionMismatch("matrices must have the same dimensions")) @invcheckoff @inbounds for j = 1:n - ia1 ← A.colptr[j] - ib1 ← B.colptr[j] - ia2 ← A.colptr[j+1] - ib2 ← B.colptr[j+1] - ia ← ia1 - ib ← ib1 + @routine begin + ia1 ← A.colptr[j] + ib1 ← B.colptr[j] + ia2 ← A.colptr[j+1] + ib2 ← B.colptr[j+1] + ia ← ia1 + ib ← ib1 + end @inbounds for i=1:ia2-ia1+ib2-ib1-1 ra ← A.rowval[ia] rb ← B.rowval[ib] @@ -60,6 +68,7 @@ end INC(ia) end end + ~@routine end - @invcheckoff branch_keeper → zeros(Bool, 2*m) + ~@routine end diff --git a/src/stdlib/statistics.jl b/src/stdlib/statistics.jl index d233796..793988a 100644 --- a/src/stdlib/statistics.jl +++ b/src/stdlib/statistics.jl @@ -54,9 +54,8 @@ end get the pdf of `Normal(μ, σ)` at point `x`. """ @i function i_normal_logpdf(out, x::T, μ, σ) where T - @zeros T anc1 anc2 anc3 - - @routine begin + @routine @invcheckoff begin + @zeros T anc1 anc2 anc3 anc1 += x anc1 -= μ anc2 += anc1 / σ # (x- μ)/σ diff --git a/test/autodiff/autodiff.jl b/test/autodiff/autodiff.jl index c09e547..8440b42 100644 --- a/test/autodiff/autodiff.jl +++ b/test/autodiff/autodiff.jl @@ -1,6 +1,7 @@ using Test, NiLang, NiLang.AD include("vars.jl") +include("stack.jl") include("gradfunc.jl") include("instructs.jl") diff --git a/test/autodiff/gradfunc.jl b/test/autodiff/gradfunc.jl index 2105569..351f5e8 100644 --- a/test/autodiff/gradfunc.jl +++ b/test/autodiff/gradfunc.jl @@ -36,6 +36,7 @@ end test1(a, b, out) (~test1)(a, b, out) a += b + out → 0.0 end # compute (a+b)*b -> out diff --git a/test/autodiff/instructs.jl b/test/autodiff/instructs.jl index c430d5a..ea30397 100644 --- a/test/autodiff/instructs.jl +++ b/test/autodiff/instructs.jl @@ -53,13 +53,13 @@ end end @testset "AD over pop" begin - @i function mean(out!, x) + @i function mean(out!::T, x) where T anc ← zero(out!) for i=1:length(x) anc += x[i] end out! += anc / (@const length(x)) - PUSH!(anc) + FLOAT64_STACK[end+1] ↔ anc::T end @test check_grad(mean, (0.0, [1,2,3.0, 4.0]); iloss=1) @@ -79,20 +79,31 @@ end @testset "push, load data" begin stack = [] - val = PUSH!(stack, [1,2,3])[2] + val = [1,2,3] + @instr PUSH!(stack, val) @test val == Int[] - val = PUSH!(stack, 3.0)[2] + val = 3.0 + @instr PUSH!(stack, val) @test val == 0.0 - PUSH!(stack, 3.0) - @test_throws InvertibilityError POP!(stack, GVar(3.0)) - PUSH!(stack, 3.0) - @test POP!(stack, GVar(0.0))[2] == GVar(3.0) + val = 3.0 + @instr PUSH!(stack, val) + x = GVar(3.0) + #@test_throws InvertibilityError @instr POP!(stack, x) + z = 3.0 + @instr PUSH!(stack, z) + z = GVar(0.0) + @instr POP!(stack, z) + @test z == GVar(3.0) x = [1.0, 2.0, 3.0] - PUSH!(stack, x) - @test POP!(stack, empty(x))[2] == GVar.([1,2,3.0]) + @instr PUSH!(stack, x) + y = empty(x) + @instr POP!(stack, y) + @test y == GVar.([1,2,3.0]) x = [1.0, 2.0, 3.0] - PUSH!(stack, x) - @test POP!(stack, empty(x))[2] == [1,2,3.0] + @instr PUSH!(stack, x) + y = empty(x) + @instr POP!(stack, y) + @test y == [1,2,3.0] end @testset "dataviews" begin diff --git a/test/autodiff/stack.jl b/test/autodiff/stack.jl new file mode 100644 index 0000000..eb8c6a8 --- /dev/null +++ b/test/autodiff/stack.jl @@ -0,0 +1,67 @@ +using NiLang, Test, NiLang.AD + +@testset "loaddata" begin + @test NiLang.loaddata(GVar(0.1), 0.3) == GVar(0.3) + @test NiLang.loaddata(Complex(GVar(0.1, 0.2), GVar(0.2)), 0.3+0.6im) == Complex(GVar(0.3), GVar(0.6)) + @test NiLang.loaddata(typeof(Complex(GVar(0.1, 0.2), GVar(0.2))), 0.3+0.6im) == Complex(GVar(0.3), GVar(0.6)) + @test NiLang.loaddata(GVar(0.2, AutoBcast{Float64,3}(zeros(3))), 0.3) == GVar(0.3, AutoBcast{Float64,3}(zeros(3))) + @test NiLang.loaddata((GVar(0.2, AutoBcast{Float64,3}(zeros(3))), 7), (0.3, 4)) == (GVar(0.3, AutoBcast{Float64,3}(zeros(3))), 4) + @test NiLang.loaddata(typeof((GVar(0.2, AutoBcast{Float64,3}(zeros(3))), 7)), (0.3, 4)) == (GVar(0.3, AutoBcast{Float64,3}(zeros(3))), 4) + @test NiLang.loaddata(4, 2.0) == 2 +end + +@testset "push load" begin + x = (0.3, 3.0, [1,2,3.0]) + @instr PUSH!(x) + t = (0.0, 0.0, Float64[]) + @test x == t && typeof(x) == typeof(t) + y = (0.0, GVar(0.0), GVar{Float64,Float64}[]) + @instr POP!(y) + t = (0.3, GVar(3.0), GVar([1,2, 3.0])) + @test y == t && typeof(y) == typeof(t) + + x = [0.3, 3.0, [1,2,3.0]] + @instr PUSH!(x) + t = [] + @test x == t && typeof(x) == typeof(t) + y = [] + @instr POP!(y) + t = [0.3, GVar(3.0), GVar([1,2, 3.0])] + @test y == t && typeof(y) == typeof(t) + + x = (0.3, 3.0, [1,2,3.0]) + @instr @invcheckoff PUSH!(x) + t = (0.0, 0.0, Float64[]) + @test x == t && typeof(x) == typeof(t) + y = (0.0, GVar(0.0), GVar(zeros(0))) + @instr @invcheckoff POP!(y) + t = (0.3, GVar(3.0), GVar([1,2, 3.0])) + @test y == t && typeof(y) == typeof(t) + + x = (0.3, 3.0, [1,2,3.0]) + @instr @invcheckoff COPYPUSH!(x) + t = (0.3, 3.0, [1,2,3.0]) + @test x == t && typeof(x) == typeof(t) + y = (0.3, GVar(t[2]), GVar(t[3])) + @instr @invcheckoff COPYPOP!(y) + t = (0.3, GVar(3.0), GVar([1,2, 3.0])) + @test y == t && typeof(y) == typeof(t) + + x = (0.3, 3.0, [1,2,3.0]) + @instr COPYPUSH!(x) + t = (0.3, 3.0, [1,2,3.0]) + @test x == t && typeof(x) == typeof(t) + y = (0.3, GVar(t[2]), GVar(t[3])) + @instr COPYPOP!(y) + t = (0.3, GVar(3.0), GVar([1,2, 3.0])) + @test y == t && typeof(y) == typeof(t) + + x = [0.3, 3.0, [1,2,3.0]] + @instr COPYPUSH!(x) + t = [0.3, 3.0, [1,2,3.0]] + @test x == t && typeof(x) == typeof(t) + y = [0.3, GVar(t[2]), GVar(t[3])] + @instr COPYPOP!(y) + t = [0.3, GVar(3.0), GVar([1,2, 3.0])] + @test y == t && typeof(y) == typeof(t) +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index f963dfe..8b4f16d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -25,10 +25,6 @@ end include("ulog.jl") end -@testset "stack.jl" begin - include("stack.jl") -end - @testset "macros.jl" begin include("macros.jl") end diff --git a/test/stack.jl b/test/stack.jl deleted file mode 100644 index 72ab7b5..0000000 --- a/test/stack.jl +++ /dev/null @@ -1,97 +0,0 @@ -using NiLang, Test -using NiLang: UNSAFE_POP!, UNSAFE_PUSH!, UNSAFE_COPYPOP!, UNSAFE_COPYPUSH! - -@testset "stack operations" begin - x =0.3 - @instr PUSH!(x) - @test x === 0.0 - @instr POP!(x) - @test x === 0.3 - @instr PUSH!(x) - x = 0.4 - @test_throws InvertibilityError @instr POP!(x) - y = 0.5 - @instr PUSH!(y) - @instr UNSAFE_POP!(x) - @test x == 0.5 - - x =0.3 - st = Float64[] - @instr PUSH!(st, x) - @test x === 0.0 - @test length(st) == 1 - @instr POP!(st, x) - @test length(st) == 0 - @test x === 0.3 - @instr PUSH!(st, x) - @test length(st) == 1 - x = 0.4 - @test_throws InvertibilityError @instr POP!(x) - @test length(st) == 1 - - y = 0.5 - @instr PUSH!(st, y) - @instr UNSAFE_POP!(st, x) - @test x == 0.5 - - @i function test(x) - x2 ← zero(x) - x2 += x^2 - PUSH!(x) - SWAP(x, x2) - end - @test test(3.0) == 9.0 - l = length(NiLang.GLOBAL_STACK) - @test check_inv(test, (3.0,)) - @test length(NiLang.GLOBAL_STACK) == l -end - -@testset "copied push/pop stack operations" begin - x =0.3 - @instr COPYPUSH!(x) - @test x === 0.3 - @instr COPYPOP!(x) - @test x === 0.3 - @instr COPYPUSH!(x) - x = 0.4 - @test_throws InvertibilityError @instr COPYPOP!(x) - y = 0.5 - @instr COPYPUSH!(y) - @instr UNSAFE_COPYPOP!(x) - @test x == 0.5 - - st = [] - x = [0.3] - @instr COPYPUSH!(st, x) - @test st[1] !== [0.3] - @test st[1] ≈ [0.3] - - x =0.3 - st = Float64[] - @instr COPYPUSH!(st, x) - @test x === 0.3 - @test length(st) == 1 - @instr COPYPOP!(st, x) - @test length(st) == 0 - @test x === 0.3 - @instr COPYPUSH!(st, x) - @test length(st) == 1 - x = 0.4 - @test_throws InvertibilityError @instr COPYPOP!(x) - @test length(st) == 1 - - y = 0.5 - @instr COPYPUSH!(st, y) - @instr UNSAFE_COPYPOP!(st, x) - @test x == 0.5 - - @i function test(x, x2) - x2 += x^2 - COPYPUSH!(x) - SWAP(x, x2) - end - @test test(3.0, 0.0) == (9.0, 3.0) - l = length(NiLang.GLOBAL_STACK) - @test check_inv(test, (3.0, 0.0)) - @test length(NiLang.GLOBAL_STACK) == l -end diff --git a/test/stdlib/bennett.jl b/test/stdlib/bennett.jl index 340de28..e2f6dd8 100644 --- a/test/stdlib/bennett.jl +++ b/test/stdlib/bennett.jl @@ -22,6 +22,7 @@ using NiLang, NiLang.AD dest[i] += dt*g ~@routine end + n → length(dest) end x = zeros(FT, n) x[n÷2] = 1