Skip to content
Snippets Groups Projects
test_refvector.jl 3.44 KiB
using Test
using BenchmarkTools
using LinearAlgebra


include("refvector.jl")
include("refblockvector.jl")


@testset "RefVector" begin

  # constructor
  v = randn(100)
  offset, n = 10, 10
  rv = RefVector(v, offset, n)

  # check if array interface works
  @test length(rv) == n
  @test v[offset:offset+n-1] == rv
  rv .*= 2.0
  rv .+= 2.0
  @test v[offset:offset+n-1] == rv

  # move reference inside v
  prev_offset, prev_n = offset, n
  offset, n = 20, 5
  update!(rv, v, offset, n)
  @test v[prev_offset:prev_offset+prev_n-1] != rv
  @test v[offset:offset+n-1] == rv

  # exchange reference for a new vector
  w = randn(100)
  update!(rv, w) # reuses offset and n
  @test v[offset:offset+n-1] != rv
  @test w[offset:offset+n-1] == rv
  update!(rv, w, prev_offset, prev_n)
  @test w[prev_offset:prev_offset+prev_n-1] == rv

  # RefVector should keep memory it references alive
  u, rv = let
    u = randn(100)
    deepcopy(u), RefVector(u)
  end
  @test u !== rv.ref
  @test u == rv

  # edge cases
  # zero length
  rv = RefVector(v, 1, 0)
  @test eltype(rv)[] == rv
  rv = RefVector(v, length(v), 0)
  @test eltype(rv)[] == rv
  # full length
  rv = RefVector(v, 1, length(v))
  @test v == rv
  # default constructor is full length
  rv = RefVector(v)
  @test v == rv

  # invalid offsets and lengths
  @test_throws ErrorException RefVector(v, -1, 10)
  @test_throws ErrorException RefVector(v, length(v), 10)
  @test_throws ErrorException RefVector(v, 1, 2*length(v))
  @test_throws ErrorException RefVector(v, 1, -1)

end


@testset "RefBlockVector" begin
  v = randn(100)
  block_sizes = [ 10 for _ = 1:5 ]
  offset = 10
  rbv = RefBlockVector(v, block_sizes, offset)
  block_offsets = cumsum(vcat(0, block_sizes[1:end-1])) .+ offset
  for (i, (bsz, bos)) in enumerate(zip(block_sizes, block_offsets))
    blk = block(rbv, i)
    @test v[bos:bos+bsz-1] == blk
  end

  # tests array interface
  @test length(rbv) == sum(block_sizes)
  @test v[offset:offset+length(rbv)-1] == rbv
  rbv .*= 2.0
  rbv .+= 2.0
  @test v[offset:offset+length(rbv)-1] == rbv

  # # custom generate eachblock
  for (bsz, bos, blk) in zip(block_sizes, block_offsets, eachblock(rbv))
    blk .*= 2.0
    @test v[bos:bos+bsz-1] == blk
  end

  # edge cases
  # no blocks
  rbv = RefBlockVector(v, Int64[], 10)
  @test eltype(rbv)[] == Float64[]
  # full length
  rbv = RefBlockVector(v, Int64[length(v)], 1)
  @test v == rbv

  # invalid offsets and lengths
  @test_throws ErrorException RefBlockVector(v, [-1,2,-10], 1)
  @test_throws ErrorException RefBlockVector(v, block_sizes, length(v))
  @test_throws ErrorException RefBlockVector(v, [1,2,3], length(v)-1)
  @test_throws ErrorException RefBlockVector(v, [1,2,3], 2*length(v))

end


@testset "Benchmark RefVector" begin

  if false

    v = randn(1000)
    offset, n = 10, 800
    rv = RefVector(v, offset, n)
    vv = v[offset:offset+n-1]
    @test vv == rv
    b = @benchmark sum($vv)
    display(b)
    b = @benchmark sum($rv)
    display(b)

    w = zeros(n)
    M = randn(n,n)
    b = @benchmark mul!($w, $M, $vv)
    display(b)
    b = @benchmark mul!($w, $M, $rv)
    display(b)

    # something with the broadcasting interface needs to be adjusted,
    # because the calls below are slower than the native arrays
    b = @benchmark $vv .= 2.0
    display(b)
    b = @benchmark $rv .= 2.0
    display(b)
    b = @benchmark $(rv.vec) .= 2.0
    display(b)

    b = @benchmark lmul!(2.0, $vv)
    display(b)
    b = @benchmark lmul!(2.0, $rv)
    display(b)

  end

end