text:
### https://tools.ietf.org/html/rfc2409#section-6.2

"""
6.1 First Oakley Default Group

   Oakley implementations MUST support a MODP group with the following
   prime and generator. This group is assigned id 1 (one).

      The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
      Its hexadecimal value is

         FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
         29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
         EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
         E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF

      The generator is: 2.
"""
function FirstOakleyGroup()
    p = hex"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
         29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
         EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
         E485B576 625E7EC6 F44C42E9 A63A3620 FFFFFFFF FFFFFFFF"
    g = 2

    # q can perhaps be recalculated assuming that generation had been
    # done with SophieGermainGroup algorithm

    return PrimeGroup(g,p,0,1024)
end

"""
6.2 Second Oakley Group

   IKE implementations SHOULD support a MODP group with the following
   prime and generator. This group is assigned id 2 (two).

   The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
   Its hexadecimal value is

         FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
         29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
         EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
         E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
         EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
         FFFFFFFF FFFFFFFF

   The generator is 2 (decimal)
"""
function SecondOakleyGroup()
    p = hex"FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
         29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
         EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
         E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
         EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
         FFFFFFFF FFFFFFFF"
    g = 2
    return PrimeGroup(g,p,0,1024)
end

### https://tools.ietf.org/html/rfc5114#section-2.1

"""
2.1.  1024-bit MODP Group with 160-bit Prime Order Subgroup

   The hexadecimal value of the prime is:

   p = B10B8F96 A080E01D DE92DE5E AE5D54EC 52C99FBC FB06A3C6
       9A6A9DCA 52D23B61 6073E286 75A23D18 9838EF1E 2EE652C0
       13ECB4AE A9061123 24975C3C D49B83BF ACCBDD7D 90C4BD70
       98488E9C 219A7372 4EFFD6FA E5644738 FAA31A4F F55BCCC0
       A151AF5F 0DC8B4BD 45BF37DF 365C1A65 E68CFDA7 6D4DA708
       DF1FB2BC 2E4A4371

   The hexadecimal value of the generator is:

   g = A4D1CBD5 C3FD3412 6765A442 EFB99905 F8104DD2 58AC507F
       D6406CFF 14266D31 266FEA1E 5C41564B 777E690F 5504F213
       160217B4 B01B886A 5E91547F 9E2749F4 D7FBD7D3 B9A92EE1
       909D0D22 63F80A76 A6A24C08 7A091F53 1DBF0A01 69B6A28A
       D662A4D1 8E73AFA3 2D779D59 18D08BC8 858F4DCE F97C2A24
       855E6EEB 22B3B2E5

   The generator generates a prime-order subgroup of size:

   q = F518AA87 81A8DF27 8ABA4E7D 64B7CB9D 49462353
"""
function MODP160Group()
    p = hex"B10B8F96 A080E01D DE92DE5E AE5D54EC 52C99FBC FB06A3C6
       9A6A9DCA 52D23B61 6073E286 75A23D18 9838EF1E 2EE652C0
       13ECB4AE A9061123 24975C3C D49B83BF ACCBDD7D 90C4BD70
       98488E9C 219A7372 4EFFD6FA E5644738 FAA31A4F F55BCCC0
       A151AF5F 0DC8B4BD 45BF37DF 365C1A65 E68CFDA7 6D4DA708
       DF1FB2BC 2E4A4371"

    g = hex"A4D1CBD5 C3FD3412 6765A442 EFB99905 F8104DD2 58AC507F
       D6406CFF 14266D31 266FEA1E 5C41564B 777E690F 5504F213
       160217B4 B01B886A 5E91547F 9E2749F4 D7FBD7D3 B9A92EE1
       909D0D22 63F80A76 A6A24C08 7A091F53 1DBF0A01 69B6A28A
       D662A4D1 8E73AFA3 2D779D59 18D08BC8 858F4DCE F97C2A24
       855E6EEB 22B3B2E5"

    q = hex"F518AA87 81A8DF27 8ABA4E7D 64B7CB9D 49462353"

    return PrimeGroup(g,p,q,1024)
end

"""
2.2.  2048-bit MODP Group with 224-bit Prime Order Subgroup

   The hexadecimal value of the prime is:

   p =  AD107E1E 9123A9D0 D660FAA7 9559C51F A20D64E5 683B9FD1
        B54B1597 B61D0A75 E6FA141D F95A56DB AF9A3C40 7BA1DF15
        EB3D688A 309C180E 1DE6B85A 1274A0A6 6D3F8152 AD6AC212
        9037C9ED EFDA4DF8 D91E8FEF 55B7394B 7AD5B7D0 B6C12207
        C9F98D11 ED34DBF6 C6BA0B2C 8BBC27BE 6A00E0A0 B9C49708
        B3BF8A31 70918836 81286130 BC8985DB 1602E714 415D9330
        278273C7 DE31EFDC 7310F712 1FD5A074 15987D9A DC0A486D
        CDF93ACC 44328387 315D75E1 98C641A4 80CD86A1 B9E587E8
        BE60E69C C928B2B9 C52172E4 13042E9B 23F10B0E 16E79763
        C9B53DCF 4BA80A29 E3FB73C1 6B8E75B9 7EF363E2 FFA31F71
        CF9DE538 4E71B81C 0AC4DFFE 0C10E64F

 g =  AC4032EF 4F2D9AE3 9DF30B5C 8FFDAC50 6CDEBE7B 89998CAF
        74866A08 CFE4FFE3 A6824A4E 10B9A6F0 DD921F01 A70C4AFA
        AB739D77 00C29F52 C57DB17C 620A8652 BE5E9001 A8D66AD7
        C1766910 1999024A F4D02727 5AC1348B B8A762D0 521BC98A
        E2471504 22EA1ED4 09939D54 DA7460CD B5F6C6B2 50717CBE
        F180EB34 118E98D1 19529A45 D6F83456 6E3025E3 16A330EF
        BB77A86F 0C1AB15B 051AE3D4 28C8F8AC B70A8137 150B8EEB
        10E183ED D19963DD D9E263E4 770589EF 6AA21E7F 5F2FF381
        B539CCE3 409D13CD 566AFBB4 8D6C0191 81E1BCFE 94B30269
        EDFE72FE 9B6AA4BD 7B5A0F1C 71CFFF4C 19C418E1 F6EC0179
        81BC087F 2A7065B3 84B890D3 191F2BFA

   The generator generates a prime-order subgroup of size:

   q =  801C0D34 C58D93FE 99717710 1F80535A 4738CEBC BF389A99
        B36371EB

"""
function MODP224Group()
    p = hex"AD107E1E 9123A9D0 D660FAA7 9559C51F A20D64E5 683B9FD1
        B54B1597 B61D0A75 E6FA141D F95A56DB AF9A3C40 7BA1DF15
        EB3D688A 309C180E 1DE6B85A 1274A0A6 6D3F8152 AD6AC212
        9037C9ED EFDA4DF8 D91E8FEF 55B7394B 7AD5B7D0 B6C12207
        C9F98D11 ED34DBF6 C6BA0B2C 8BBC27BE 6A00E0A0 B9C49708
        B3BF8A31 70918836 81286130 BC8985DB 1602E714 415D9330
        278273C7 DE31EFDC 7310F712 1FD5A074 15987D9A DC0A486D
        CDF93ACC 44328387 315D75E1 98C641A4 80CD86A1 B9E587E8
        BE60E69C C928B2B9 C52172E4 13042E9B 23F10B0E 16E79763
        C9B53DCF 4BA80A29 E3FB73C1 6B8E75B9 7EF363E2 FFA31F71
        CF9DE538 4E71B81C 0AC4DFFE 0C10E64F"

    g = hex"AC4032EF 4F2D9AE3 9DF30B5C 8FFDAC50 6CDEBE7B 89998CAF
        74866A08 CFE4FFE3 A6824A4E 10B9A6F0 DD921F01 A70C4AFA
        AB739D77 00C29F52 C57DB17C 620A8652 BE5E9001 A8D66AD7
        C1766910 1999024A F4D02727 5AC1348B B8A762D0 521BC98A
        E2471504 22EA1ED4 09939D54 DA7460CD B5F6C6B2 50717CBE
        F180EB34 118E98D1 19529A45 D6F83456 6E3025E3 16A330EF
        BB77A86F 0C1AB15B 051AE3D4 28C8F8AC B70A8137 150B8EEB
        10E183ED D19963DD D9E263E4 770589EF 6AA21E7F 5F2FF381
        B539CCE3 409D13CD 566AFBB4 8D6C0191 81E1BCFE 94B30269
        EDFE72FE 9B6AA4BD 7B5A0F1C 71CFFF4C 19C418E1 F6EC0179
        81BC087F 2A7065B3 84B890D3 191F2BFA"

   q =  hex"801C0D34 C58D93FE 99717710 1F80535A 4738CEBC BF389A99
        B36371EB"

    return PrimeGroup(g,p,q,2048)
end

"""
2.3.  2048-bit MODP Group with 256-bit Prime Order Subgroup

   The hexadecimal value of the prime is:

   p = 87A8E61D B4B6663C FFBBD19C 65195999 8CEEF608 660DD0F2
       5D2CEED4 435E3B00 E00DF8F1 D61957D4 FAF7DF45 61B2AA30
       16C3D911 34096FAA 3BF4296D 830E9A7C 209E0C64 97517ABD
       5A8A9D30 6BCF67ED 91F9E672 5B4758C0 22E0B1EF 4275BF7B
       6C5BFC11 D45F9088 B941F54E B1E59BB8 BC39A0BF 12307F5C
       4FDB70C5 81B23F76 B63ACAE1 CAA6B790 2D525267 35488A0E
       F13C6D9A 51BFA4AB 3AD83477 96524D8E F6A167B5 A41825D9
       67E144E5 14056425 1CCACB83 E6B486F6 B3CA3F79 71506026
       C0B857F6 89962856 DED4010A BD0BE621 C3A3960A 54E710C3
       75F26375 D7014103 A4B54330 C198AF12 6116D227 6E11715F
       693877FA D7EF09CA DB094AE9 1E1A1597

       The hexadecimal value of the generator is:

   g = 3FB32C9B 73134D0B 2E775066 60EDBD48 4CA7B18F 21EF2054
       07F4793A 1A0BA125 10DBC150 77BE463F FF4FED4A AC0BB555
       BE3A6C1B 0C6B47B1 BC3773BF 7E8C6F62 901228F8 C28CBB18
       A55AE313 41000A65 0196F931 C77A57F2 DDF463E5 E9EC144B
       777DE62A AAB8A862 8AC376D2 82D6ED38 64E67982 428EBC83
       1D14348F 6F2F9193 B5045AF2 767164E1 DFC967C1 FB3F2E55
       A4BD1BFF E83B9C80 D052B985 D182EA0A DB2A3B73 13D3FE14
       C8484B1E 052588B9 B7D2BBD2 DF016199 ECD06E15 57CD0915
       B3353BBB 64E0EC37 7FD02837 0DF92B52 C7891428 CDC67EB6
       184B523D 1DB246C3 2F630784 90F00EF8 D647D148 D4795451
       5E2327CF EF98C582 664B4C0F 6CC41659

   The generator generates a prime-order subgroup of size:

   q = 8CF83642 A709A097 B4479976 40129DA2 99B1A47D 1EB3750B
       A308B0FE 64F5FBD3
"""
function MODP256Group()
    p = hex"AD107E1E 9123A9D0 D660FAA7 9559C51F A20D64E5 683B9FD1
        B54B1597 B61D0A75 E6FA141D F95A56DB AF9A3C40 7BA1DF15
        EB3D688A 309C180E 1DE6B85A 1274A0A6 6D3F8152 AD6AC212
        9037C9ED EFDA4DF8 D91E8FEF 55B7394B 7AD5B7D0 B6C12207
        C9F98D11 ED34DBF6 C6BA0B2C 8BBC27BE 6A00E0A0 B9C49708
        B3BF8A31 70918836 81286130 BC8985DB 1602E714 415D9330
        278273C7 DE31EFDC 7310F712 1FD5A074 15987D9A DC0A486D
        CDF93ACC 44328387 315D75E1 98C641A4 80CD86A1 B9E587E8
        BE60E69C C928B2B9 C52172E4 13042E9B 23F10B0E 16E79763
        C9B53DCF 4BA80A29 E3FB73C1 6B8E75B9 7EF363E2 FFA31F71
        CF9DE538 4E71B81C 0AC4DFFE 0C10E64F"

    g = hex"AC4032EF 4F2D9AE3 9DF30B5C 8FFDAC50 6CDEBE7B 89998CAF
        74866A08 CFE4FFE3 A6824A4E 10B9A6F0 DD921F01 A70C4AFA
        AB739D77 00C29F52 C57DB17C 620A8652 BE5E9001 A8D66AD7
        C1766910 1999024A F4D02727 5AC1348B B8A762D0 521BC98A
        E2471504 22EA1ED4 09939D54 DA7460CD B5F6C6B2 50717CBE
        F180EB34 118E98D1 19529A45 D6F83456 6E3025E3 16A330EF
        BB77A86F 0C1AB15B 051AE3D4 28C8F8AC B70A8137 150B8EEB
        10E183ED D19963DD D9E263E4 770589EF 6AA21E7F 5F2FF381
        B539CCE3 409D13CD 566AFBB4 8D6C0191 81E1BCFE 94B30269
        EDFE72FE 9B6AA4BD 7B5A0F1C 71CFFF4C 19C418E1 F6EC0179
        81BC087F 2A7065B3 84B890D3 191F2BFA"

    q = hex"8CF83642 A709A097 B4479976 40129DA2 99B1A47D 1EB3750B
       A308B0FE 64F5FBD3"

    return PrimeGroup(g,p,q,2048)
end


text:
function action(prob::GameProblem; time=false)
    """
       Solve problem and return array of one-step actions
    """

    if time
        @time newton_solve!(prob)
    else
        newton_solve!(prob)
    end
    u = controls(prob.pdtraj.pr)
    return u[1]
end

ext: jl

max_stars_repo_name: lassepe/DecNashPlanning

max_issues_repo_name: lassepe/DecNashPlanning

max_forks_repo_name: lassepe/DecNashPlanning


text:
using DelimitedFiles

content = readdlm("input.txt", ' ')

mutable struct SubmarineState
    x::Int
    y::Int
    aim::Int
end

p = SubmarineState(0, 0, 0)

function modifyState(instruction)
    command, value = instruction
    if command == "forward"
        p.x += value
        p.y += p.aim * value
    elseif command == "down"
        p.aim += value
    else
        p.aim -= value
    end
end

for i in 1:length(content[:, 1])
    modifyState(content[i, :])
end

p.x * p.y

max_stars_repo_path: Day 2/part2.jl

max_issues_repo_path: Day 2/part2.jl

max_forks_repo_path: Day 2/part2.jl


text:
# Example for 2D sparsity-promoting LSRTM with source subsampling
# Author: Philipp Witte, pwitte@eos.ubc.ca
# Date: January 2017
#

using PyCall
using PyPlot
using opesciSLIM.TimeModeling
using opesciSLIM.LeastSquaresMigration

## Set up model structure
n = (120,100)	# (x,y,z) or (x,z)
d = (10.,10.)
o = (0.,0.)

# Velocity [km/s]
v = ones(Float32,n) + 0.4f0
v0 = ones(Float32,n) + 0.4f0
v[:,40:70] = 3.0f0
v[:,71:end] = 4.0f0
rho = ones(Float32,n)

# Slowness squared [s^2/km^2]
m = (1./v).^2
m0 = (1./v0).^2
dm = vec(m - m0)

# Setup info and model structure
nsrc = 4
model = Model(n,d,o,m)	# to include density call Model(n,d,o,m,rho)
model0 = Model(n,d,o,m0)

## Set up receiver geometry
nxrec = 120
xrec = linspace(50.,1150.,nxrec)
yrec = 0.
zrec = linspace(50.,50.,nxrec)

# receiver sampling and recording time
timeR = 1000.	# receiver recording time [ms]
dtR = 4.	# receiver sampling interval

# Set up receiver structure
recGeometry = Geometry(xrec,yrec,zrec;dt=dtR,t=timeR,nsrc=nsrc)

## Set up source geometry (cell array with source locations for each shot)
xsrc = convertToCell(linspace(100,1000,nsrc))
ysrc = convertToCell(linspace(0,0,nsrc))
zsrc = convertToCell(linspace(20,20,nsrc))

# source sampling and number of time steps
timeS = 1000.	# source length in [ms]
dtS = 2.	# source sampling interval

# Set up source structure
srcGeometry = Geometry(xsrc,ysrc,zsrc;dt=dtS,t=timeS)

# setup wavelet
f0 = 0.01
wavelet = source(timeS,dtS,f0)

# Info structure for linear operators
ntComp = get_computational_nt(srcGeometry,recGeometry,model)	# no. of computational time steps
info = Info(prod(n),nsrc,ntComp)

###################################################################################################

# Setup operators
F = joModeling(info,model0,srcGeometry,recGeometry)
q = joData(srcGeometry,wavelet)
J = joJacobian(F,q)

# Observed data
dD = J*dm

# Least squares migration
image = linbreg_lsrtm(J, dD; iterations=5, shots_per_iteration=2)

max_stars_repo_name: SINBADconsortium/SLIM-release-jlapps

max_issues_repo_name: SINBADconsortium/SLIM-release-jlapps

max_forks_repo_name: SINBADconsortium/SLIM-release-jlapps


text:
@testset "insert_some_elements.jl" begin
    @testset "elements = vector" begin
        using Random: seed!
        using StatsBase: sample

        seed!(1234)

        for i in 0:10
            X=[1:10;]
            indices = sort(sample(1:length(X),i,replace=false))
            elements=X[indices]

            X_deflated = deleteat!(copy(X),indices)
            X_recons = insert_some_elements(X_deflated,indices,elements)

            @test X_recons == X
        end
    end

    @testset "elements = constant" begin
        using Random: seed!
        using StatsBase: sample

        seed!(1234)

        for i in 0:10
            X=[1:10;]
            indices = sort(sample(1:length(X),i,replace=false))
            element = 2021
            X[indices] .= element

            X_deflated = deleteat!(copy(X),indices)
            X_recons = insert_some_elements(X_deflated,indices,element)

            @test X_recons == X
        end
    end
end


text:
import CpuId, Libdl

let llvmlib = Libdl.dlopen(only(filter(lib->occursin(r"LLVM\b", basename(lib)), Libdl.dllist()))),
    gethostcpufeatures = Libdl.dlsym(llvmlib, :LLVMGetHostCPUFeatures),
    features_cstring = ccall(gethostcpufeatures, Cstring, ()),
    features = filter(ext -> (m = match(r"\d", ext); isnothing(m) ? true : m.offset != 2 ), split(unsafe_string(features_cstring), ','))

    offsetnottwo(::Nothing) = true
    offsetnottwo(m::RegexMatch) = m.offset != 2

    avx512f = any(isequal("+avx512f"), features)
    avx2 = any(isequal("+avx2"), features)
    avx = any(isequal("+avx"), features)

    register_size = avx512f ? 64 : (avx ? 32 : 16)
    register_count = avx512f ? 32 : 16
    cache_size = CpuId.cachesize()
    num_cores = CpuId.cpucores()

    @eval const REGISTER_SIZE = $register_size
    @eval const REGISTER_COUNT = $register_count
    @eval const FP256 = $(CpuId.cpufeature(CpuId.FP256)) # Is AVX2 fast?
    @eval const CACHELINE_SIZE = $(CpuId.cachelinesize())
    @eval const CACHE_SIZE = $cache_size
    @eval const NUM_CORES = $num_cores
    @eval const SIMD_NATIVE_INTEGERS = $(avx2)

    for ext ∈ features
        @eval const $(Symbol(replace(Base.Unicode.uppercase(ext[2:end]), r"\." => "_"))) = $(first(ext) == '+')
    end
    Libc.free(features_cstring)
end

const FMA3 = FMA


text:
### jacobisymbol

# `jacobisymbol(a,n)` returns the Jacobi symbol. This is limited to bitstype integers.
# This is faster than Combinatorics.jacobisymbol for bitstype inputs, but slower for
#     BigInt inputs. Thus, these methods are complementary.

export jacobisymbol

macro flip!(n) :($(esc(n)) = -$(esc(n))) end
function jacobisymbol(a::Union{Signed,Unsigned},n::Union{Signed,Unsigned})
    if n <= 0 || iseven(n) throw(DomainError()) end
    j = 1
    if n < 0
        n % 4 == 3  ? @flip!(j)  : nothing
        @flip!(n)
    end
    while a != 0
        while iseven(a)
            n % 8 == 3 || n % 8 == 5 ? @flip!(j) : nothing
            a >>= 1
        end
        (a,n) = (n,a)
        a % 4 == 3 && n % 4 == 3 ? @flip!(j) : nothing
        a %= n
    end
    return n == 1 ? j : 0
end

#Base.@vectorize_2arg Union{Signed,Unsigned} jacobisymbol


text:
# Define a bunch of configs for testing purposes
struct MostBoringConfig <: RuleConfig{Union{}} end

struct MockForwardsConfig <: RuleConfig{Union{HasForwardsMode,NoReverseMode}}
    forward_calls::Vector
end
MockForwardsConfig() = MockForwardsConfig([])
function ChainRulesCore.frule_via_ad(config::MockForwardsConfig, ȧrgs, f, args...; kws...)
    # For testing purposes we only support giving right answer for identity functions
    push!(config.forward_calls, (f, args))
    return f(args...; kws...), ȧrgs
end

struct MockReverseConfig <: RuleConfig{Union{NoForwardsMode,HasReverseMode}}
    reverse_calls::Vector
end
MockReverseConfig() = MockReverseConfig([])
function ChainRulesCore.rrule_via_ad(config::MockReverseConfig, f, args...; kws...)
    # For testing purposes we only support giving right answer for identity functions
    push!(config.reverse_calls, (f, args))
    pullback_via_ad(ȳ) = NoTangent(), ȳ
    return f(args...; kws...), pullback_via_ad
end

struct MockBothConfig <: RuleConfig{Union{HasForwardsMode,HasReverseMode}}
    forward_calls::Vector
    reverse_calls::Vector
end
MockBothConfig() = MockBothConfig([], [])
function ChainRulesCore.frule_via_ad(config::MockBothConfig, ȧrgs, f, args...; kws...)
    # For testing purposes we only support giving right answer for identity functions
    push!(config.forward_calls, (f, args))
    return f(args...; kws...), ȧrgs
end

function ChainRulesCore.rrule_via_ad(config::MockBothConfig, f, args...; kws...)
    # For testing purposes we only support giving right answer for identity functions
    push!(config.reverse_calls, (f, args))
    pullback_via_ad(ȳ) = NoTangent(), ȳ
    return f(args...; kws...), pullback_via_ad
end

##############################

#define some functions for testing

@testset "config.jl" begin
    @testset "basic fall to two arg verion for $Config" for Config in (
        MostBoringConfig, MockForwardsConfig, MockReverseConfig, MockBothConfig
    )
        counting_id_count = Ref(0)
        function counting_id(x)
            counting_id_count[] += 1
            return x
        end
        function ChainRulesCore.rrule(::typeof(counting_id), x)
            counting_id_pullback(x̄) = x̄
            return counting_id(x), counting_id_pullback
        end
        function ChainRulesCore.frule((dself, dx), ::typeof(counting_id), x)
            return counting_id(x), dx
        end
        @testset "rrule" begin
            counting_id_count[] = 0
            @test rrule(Config(), counting_id, 21.5) !== nothing
            @test counting_id_count[] == 1
        end
        @testset "frule" begin
            counting_id_count[] = 0
            @test frule(Config(), (NoTangent(), 11.2), counting_id, 32.4) !== nothing
            @test counting_id_count[] == 1
        end
    end

    @testset "hitting forwards AD" begin
        do_thing_2(f, x) = f(x)
        function ChainRulesCore.frule(
            config::RuleConfig{>:HasForwardsMode}, (_, df, dx), ::typeof(do_thing_2), f, x
        )
            return frule_via_ad(config, (df, dx), f, x)
        end

        @testset "$Config" for Config in (MostBoringConfig, MockReverseConfig)
            @test nothing === frule(
                Config(), (NoTangent(), NoTangent(), 21.5), do_thing_2, identity, 32.1
            )
        end

        @testset "$Config" for Config in (MockBothConfig, MockForwardsConfig)
            bconfig = Config()
            @test nothing !== frule(
                bconfig, (NoTangent(), NoTangent(), 21.5), do_thing_2, identity, 32.1
            )
            @test bconfig.forward_calls == [(identity, (32.1,))]
        end
    end

    @testset "hitting reverse AD" begin
        do_thing_3(f, x) = f(x)
        function ChainRulesCore.rrule(
            config::RuleConfig{>:HasReverseMode}, ::typeof(do_thing_3), f, x
        )
            return (NoTangent(), rrule_via_ad(config, f, x)...)
        end

        @testset "$Config" for Config in (MostBoringConfig, MockForwardsConfig)
            @test nothing === rrule(Config(), do_thing_3, identity, 32.1)
        end

        @testset "$Config" for Config in (MockBothConfig, MockReverseConfig)
            bconfig = Config()
            @test nothing !== rrule(bconfig, do_thing_3, identity, 32.1)
            @test bconfig.reverse_calls == [(identity, (32.1,))]
        end
    end

    @testset "hitting forwards AD from reverse, if available and reverse if not" begin
        # this is is the complicated case doing something interesting and pseudo-mixed mode
        do_thing_4(f, x) = f(x)
        function ChainRulesCore.rrule(
            config::RuleConfig{>:HasForwardsMode},
            ::typeof(do_thing_4),
            f::Function,
            x::Real,
        )
            # real code would support functors/closures, but in interest of keeping example short we exclude it:
            @assert (fieldcount(typeof(f)) == 0) "Functors/Closures are not supported"

            ẋ = one(x)
            y, ẏ = frule_via_ad(config, (NoTangent(), ẋ), f, x)
            pullback_via_forwards_ad(ȳ) = NoTangent(), NoTangent(), ẏ * ȳ
            return y, pullback_via_forwards_ad
        end
        function ChainRulesCore.rrule(
            config::RuleConfig{>:Union{HasReverseMode,NoForwardsMode}},
            ::typeof(do_thing_4),
            f,
            x,
        )
            y, f_pullback = rrule_via_ad(config, f, x)
            do_thing_4_pullback(ȳ) = (NoTangent(), f_pullback(ȳ)...)
            return y, do_thing_4_pullback
        end

        @test nothing === rrule(MostBoringConfig(), do_thing_4, identity, 32.1)

        @testset "$Config" for Config in (MockBothConfig, MockForwardsConfig)
            bconfig = Config()
            @test nothing !== rrule(bconfig, do_thing_4, identity, 32.1)
            @test bconfig.forward_calls == [(identity, (32.1,))]
        end

        rconfig = MockReverseConfig()
        @test nothing !== rrule(rconfig, do_thing_4, identity, 32.1)
        @test rconfig.reverse_calls == [(identity, (32.1,))]
    end

    @testset "RuleConfig broadcasts like a scaler" begin
        @test (MostBoringConfig() .=> (1, 2, 3)) isa NTuple{3,Pair{MostBoringConfig,Int}}
    end

    @testset "fallbacks" begin
        no_rule(x; kw="bye") = error()
        @test frule((1.0,), no_rule, 2.0) === nothing
        @test frule((1.0,), no_rule, 2.0; kw="hello") === nothing
        @test frule(MostBoringConfig(), (1.0,), no_rule, 2.0) === nothing
        @test frule(MostBoringConfig(), (1.0,), no_rule, 2.0; kw="hello") === nothing
        @test rrule(no_rule, 2.0) === nothing
        @test rrule(no_rule, 2.0; kw="hello") === nothing
        @test rrule(MostBoringConfig(), no_rule, 2.0) === nothing
        @test rrule(MostBoringConfig(), no_rule, 2.0; kw="hello") === nothing

        # Test that incorrect use of the fallback rules correctly throws MethodError
        @test_throws MethodError frule()
        @test_throws MethodError frule(; kw="hello")
        @test_throws MethodError frule(sin)
        @test_throws MethodError frule(sin; kw="hello")
        @test_throws MethodError frule(MostBoringConfig())
        @test_throws MethodError frule(MostBoringConfig(); kw="hello")
        @test_throws MethodError frule(MostBoringConfig(), sin)
        @test_throws MethodError frule(MostBoringConfig(), sin; kw="hello")
        @test_throws MethodError rrule()
        @test_throws MethodError rrule(; kw="hello")
        @test_throws MethodError rrule(MostBoringConfig())
        @test_throws MethodError rrule(MostBoringConfig(); kw="hello")
    end
end


text:
module DomainContributionsTests

using Test
using FillArrays
using Gridap.Helpers
using Gridap.Fields
using Gridap.ReferenceFEs
using Gridap.Arrays
using Gridap.Integration
using Gridap.CellData
using Gridap.TensorValues
using Gridap.Geometry

domain = (0,1,0,1)
cells = (2,2)
model = simplexify(CartesianDiscreteModel(domain,cells))

Ω = Triangulation(model)
Γ = BoundaryTriangulation(model)
Λ = SkeletonTriangulation(model)
n_Λ = get_normal_vector(Λ)

degree = 2
dΩ = Measure(Ω,degree)
dΓ = Measure(Γ,degree)
dΛ = Measure(Λ,degree)

v = GenericCellField(get_cell_shapefuns(Ω),Ω,ReferenceDomain())
u = GenericCellField(lazy_map(transpose,get_data(v)),v.trian,v.domain_style)

a = ∫(u*v)*dΩ + ∫(u*v)*dΓ + ∫(∇(u)⋅∇(v))*dΩ
@test num_domains(a) == 2
@test Ω in get_domains(a)
@test Γ in get_domains(a)
@test isa(get_contribution(a,Ω),LazyArray)

a = ∫(1)*dΩ + ∫(1)*dΓ
@test sum(a) ≈ 5
@test sum(2*a) ≈ 10
@test sum(a*2) ≈ 10

u = CellField(x->2*x[1],Ω)
v = CellField(x->3*x[2],Ω)

a = ∫(jump(u))*dΛ
@test sum(a) + 1 ≈ 1

a = ∫( (n_Λ.⁺⋅∇(v.⁻))*jump(n_Λ⋅∇(u)) )*dΛ
@test sum(a) + 1 ≈ 1

end # module


text:
# Benchmark XXX
using BenchmarkTools
# Every benchmark module creates and populates a group.
const SUITE = BenchmarkGroup()

@benchmarkable


text:
module RSUOptimizationVis

using PyCall
using OpenStreetMapX
using RSUOptimization

export visualize_RSUs_and_failures, visualize_bounds

include("visualization.jl")

end


text:
########################### Stopping Criteria ###################################

# could generally be function of f, x, (d), α, t

# compositie stopping critera
# struct Any{T, A<:Tuple{Vararg{StoppingCriterion}}} <: StoppingCriterion{T}
#     args::A
# end
# (T::Any)(x, f, g, t) = any(c(x, f, g, t) for c in T.args)
#
# struct All{T, A<:Tuple{Vararg{StoppingCriterion}}} <: StoppingCriterion{T}
#     args::A
# end
# (T::All)(x, f, g, t) = all(c(x, f, g, t) for c in T.args)

# this is closest to the definition of fixed point finding
# struct XStop{T, V} <: StoppingCriterion{T}
#     ε::T
#     x::V
# end
# (T::XStop)(x::AbstractVector) = norm(difference(x, T.x)) < ε
# update!(T::XStop, x) = (T.x .= x) # update the stopping criterion
#
# # if function value does not decay enough (could be done in step size selection?)
# # should this be mutable since old_y is scalar but has to change (same with TStop)
# mutable struct YStop{T} <: StoppingCriterion{T}
#     δ::T
#     old_y::T
# end

# if we reach maximum iterations
# struct TStop{T} <: StoppingCriterion
#     max::Int
#    i::Int
# end

# if gradient falls below zero (more generally increment?)
# struct GradientStop{T} <: StoppingCriterion{T}
#     ε::T
# end


text:
using Documenter, CodecLz4

makedocs(;
    modules=[CodecLz4],
    format=Documenter.HTML(),
    pages=[
        "Home" => "index.md",
    ],
    repo="https://github.com/JuliaIO/CodecLz4.jl/blob/{commit}{path}#L{line}",
    sitename="CodecLz4.jl",
    authors="Invenia Technical Computing Corporation",
)

deploydocs(;
    repo="github.com/JuliaIO/CodecLz4.jl",
    target="build",
    deps=nothing,
    make=nothing,
)


text:
#=----------------------------------------------------------------------------

Copyright (c) 2015 Peter Kovesi
pk@peterkovesi.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

The Software is provided "as is", without warranty of any kind.

----------------------------------------------------------------------------=#

# Definition of some utility functions that are used by the colour map
# generation code.  These functions will eventually move into an image
# processing package that I am slowing building

export bbspline, pbspline, gaussfilt1d, interp1, matprint
export normalise, normalize
export histtruncate
export sineramp, circlesineramp

#-----------------------------------------------------------------------
"""
bbspline - Basic B-spline
```
Usage:  S = bbspline(P, k, N)

Arguments:   P - [dim x Npts] array of control points
             k - order of spline (>= 2).
                 k = 2: Linear
                 k = 3: Quadratic, etc
             N - Optional number of points to evaluate along
                 spline. Defaults to 100.

Returns:     S - spline curve  [dim x N] spline points
```
See also: pbspline
"""
function bbspline(P::AbstractMatrix, k::Int, N::Int = 100)
    # PK Jan 2014

    (dim, np1) = size(P)
    n = np1-1

    @assert k >= 2   "Spline order must be 2 or greater"
    @assert np1 >= k "No of control points must be >= k"
    @assert N >= 2   "Spline must be evaluated at 2 or more points"

    # Set up open uniform knot vector from 0 - 1.
    # There are k repeated knots at each end.
    ti = collect(0:(k+n - 2*(k-1)))'
    ti = ti/ti[end]
    ti = [repeat([ti[1]], 1, k-1)  ti  repeat([ti[end]], 1, k-1)]

    nK = length(ti)

    # Generate values of t that the spline will be evaluated at
    dt = (ti[end]-ti[1])/(N-1)
    t = collect(ti[1]:dt:ti[end])'

    # Build complete array of basis functions.  We maintain two
    # arrays, one storing the basis functions at the current level of
    # recursion, and one storing the basis functions from the previous
    # level of recursion
    Blast = Array{Array{Float64}}(undef, nK-1)
    B = Array{Array{Float64}}(undef, nK-1)

    # 1st level of recursive construction
    for i = 1:nK-1
        if ti[i] < ti[i+1]
            Blast[i] = (t .>= ti[i]) .& (t .< ti[i+1])
        else
            Blast[i] = zeros(1,N)
        end
    end

    # Subsequent levels of recursive basis construction.  Note the logic to
    # handle repeated knot values where ti[i] == ti[i+1]
    for ki = 2:k
        for i = 1:nK-ki
            if (ti[i+ki-1] - ti[i]) < eps()
                V1 = zeros(1,N)
            else
                V1 = (t .- ti[i])/(ti[i+ki-1] - ti[i]) .* Blast[i]
            end

            if (ti[i+ki] - ti[i+1]) < eps()
                V2 = zeros(1,N)
            else
                V2 = (ti[i+ki] .- t)/(ti[i+ki] - ti[i+1]) .* Blast[i+1]
            end

            B[i] = V1 + V2

            # This is the ideal equation that the code above implements
            # B[i,ki] = (t - ti[i])/(ti[i+ki-1] - ti[i]) .* B[i,ki-1] + ...
            #           (ti[i+ki] - t)/(ti[i+ki] - ti[i+1]) .* B[i+1,ki-1]
        end
        # Swap B and Blast, but only if this is not the last iteration
        if ki < k
            tmp = Blast
            Blast = B
            B = tmp
        end
    end

    # Apply basis functions to the control points
    S = zeros(dim, length(t))

    for d = 1:dim, i = 1:np1
        S[d:d,:] += P[d,i]*B[i]
    end

    # Set the last point of the spline. This is not evaluated by the code above
    # because the basis functions are defined from ti[i] <= t < ti[i+1]
    S[:,end] = P[:,end]

    return S
end

#-------------------------------------------------------------------------------
"""
pbspline - Basic Periodic B-spline
```
Usage:  S = pbspline(P, k, N)

Arguments:   P - [dim x Npts] array of control points
             k - order of spline (>= 2).
                 k = 2: Linear
                 k = 3: Quadratic, etc
             N - Optional number of points to evaluate along
                 spline. Defaults to 100.

Returns:     S - spline curve  [dim x N] spline points
```
Note that the spline points are rotated so that the first point is as
close as possible to the first control point.  This is important for
the formation of cyclic paths in colour space.

See also: bbspline
"""
function pbspline(Pin::AbstractArray, k::Int, N::Int = 100)
    # PK March 2014
    # Needs a bit of tidying up and checking on domain of curve
    # Should be merged with bbspline
    # Issue: If N is too small one can get out of bounds errors at line 193

    P = copy(Pin)  # Make a copy because we will be altering P

    # For a closed spline check if 1st and last control points match.  If not
    # add another control point so that they do match
    if norm(P[:,1] - P[:,end]) > 0.01
        P = [P P[:,1]]
    end

    # Now add k - 1 control points that wrap over the first control points
    P = [P P[:,2:2+k-1]]

    (dim, np1) = size(P)
    n = np1-1

    @assert k >= 2   "Spline order must be 2 or greater"
    @assert np1 >= k "No of control points must be >= k"
    @assert N >= 2   "Spline must be evaluated at 2 or more points"

    # Form a uniform sequence. Number of knot points is m + 1 where m = n + k + 1
    ti = collect(0:(n+k+1))/(n+k+1)'
    nK = length(ti)

    # Domain of curve is [ti_k to ti_n] or [ti_(k+1) to ti_(n+1)] ???
    tstart = ti[k]
    tend = ti[n]

    dt = (tend-tstart)/(N-1)
    t = collect(tstart:dt:tend)'

    # Build complete array of basis functions.  We maintain two
    # arrays, one storing the basis functions at the current level of
    # recursion, and one storing the basis functions from the previous
    # level of recursion
    Blast = Array{Array{Float64}}(undef, nK-1)
    B = Array{Array{Float64}}(undef, nK-1)

    # 1st level of recursive construction
    for i = 1:nK-1
        if t[i] < ti[i+1]
            Blast[i] = (t .>= ti[i]) .& (t .< ti[i+1])
        else
            Blast[i] = zeros(1,N)
        end
    end

    # Subsequent levels of recursive basis construction.  Note the logic to
    # handle repeated knot values where ti[i] == ti[i+1]
    for ki = 2:k
        for i = 1:nK-ki

            if (ti[i+ki-1] - ti[i]) < eps()
                V1 = zeros(1,N)
            else
                V1 = (t .- ti[i])/(ti[i+ki-1] - ti[i]) .* Blast[i]
            end

            if (ti[i+ki] - ti[i+1]) < eps()
                V2 = zeros(1,N)
            else
                V2 = (ti[i+ki] .- t)/(ti[i+ki] - ti[i+1]) .* Blast[i+1]
            end

            B[i] = V1 + V2

            #       This is the ideal equation that the code above implements
            #       B[i,ki] = (t - ti[i])/(ti[i+ki-1] - ti[i]) .* B[i,ki-1] + ...
            #                (ti[i+ki] - t)/(ti[i+ki] - ti[i+1]) .* B[i+1,ki-1]
        end
        # Swap B and Blast, but only if this is not the last iteration
        if ki < k
            tmp = Blast
            Blast = B
            B = tmp
        end
    end

    # Apply basis functions to the control points
    S = zeros(dim, length(t))

    for d = 1:dim, i = 1:np1
        S[d:d,:] += P[d,i]*B[i]
    end

    # Finally, because of the knot arrangements, the start of the spline may not
    # be close to the first control point if the spline order is 3 or greater.
    # Normally for a closed spline this is irrelevant.  However for our purpose
    # of using closed b splines to form paths in a colour space this is important to
    # us.  The simple brute force solution used here is to search through the
    # spline points for the point that is closest to the 1st control point and
    # then rotate the spline points accordingly

    distsqrd = zeros(size(S[1,:]))
    for d = 1:dim
        distsqrd += (S[d,:] .- P[d,1]).^2
    end

    ind = argmin(distsqrd)

    return S = circshift(S, [0, -ind+1])
end

#----------------------------------------------------------------------------
# Function for applying a 1D Gaussian filter to a signal. Filtering at
# ends are done using zero padding
#
# Usage: sm = gaussfilt1d(s::Array, sigma::Real)

function gaussfilt1d(s::Array, sigma::Real)

    N = length(s)

    r = ceil(Int, 3*sigma)    # Determine filter size
    fw = 2*r + 1

    # Construct filter
    f = Float64[exp(-x.^2/(2*sigma)) for x = -r:r]
    f = f/sum(f)

    sm = zeros(size(s))

    # Filter centre section
    for i = r+1:N-r, k = 1:fw
        sm[i] += f[k] * s[i+k-r-1]
    end

    # Filter start section of array using 0 padding
    for i = 1:r, k = 1:fw
        ind = i+k-r-1
        if ind >= 1 && ind <= N
            sm[i] += f[k] * s[ind]
        end
    end

    # Filter end section of array using 0 padding
    for i = N-r+1:N, k = 1:fw
        ind = i+k-r-1
        if ind >= 1 && ind <= N
            sm[i] += f[k] * s[ind]
        end
    end

    return sm
end

#----------------------------------------------------------------------------
"""
Simple 1D linear interpolation of an array of data

```
 Usage:  yi = interp1(x, y, xi)

Arguments:  x - Array of coordinates at which y is defined.
            y - Array of values at coordinates x.
           xi - Coordinate locations at which you wish to interpolate y values.

Returns:   yi - Values linearly interpolated from y at xi.

```
Interpolates y, defined at values x, at locations xi and returns the
corresponding values as yi

x is assumed increasing but not necessarily equi-spaced.
xi values do not need to be sorted.

If any xi are outside the range of x then the corresponding value of
yi is set to the appropriate end value of y.

"""
function interp1(x, y, xi)

    N = length(xi)
    yi = zeros(size(xi))

    minx = minimum(x)
    maxx = maximum(x)

    for i = 1:N
        # Find interval in x that each xi lies within and interpolate its value

        if xi[i] <= minx
            yi[i] = y[1]

        elseif xi[i] >= maxx
            yi[i] = y[end]

        else
            left = maximum(findall(x .<= xi[i]))
            right = minimum(findall(x .> xi[i]))

            yi[i] = y[left] +  (xi[i]-x[left])/(x[right]-x[left]) * (y[right] - y[left])
        end
    end

    return yi
end

#----------------------------------------------------------------------------

function matprint(arr, str="")

    @printf("\n%s\n",str)

    if ndims(arr) == 1
        (rows,) = size(arr)
        @printf("[")
        for r=1:rows
            if r < rows
                @printf("%.3f, ",arr[r])
            else
                @printf("%.3f",arr[r])
            end
        end
        @printf("]\n")

    elseif ndims(arr) == 2
        (rows,cols) = size(arr)

        @printf("[")
        for r=1:rows
            if r>1
                @printf(" ")
            end
            for c=1:cols
                @printf("%.3f ",arr[r,c])
            end
            if r<rows
                @printf("\n")
            else
                @printf("]\n")
            end
        end
    end
end

#----------------------------------------------------------------------
"""
normalise/normalize - Normalises image values to 0-1, or to desired mean and variance

```
Usage 1:      nimg = normalise(img)
```
Offsets and rescales image so that the minimum value is 0
and the maximum value is 1.

```
Usage 2:      nimg = normalise(img, reqmean, reqvar)

Arguments:  img     - A grey-level input image.
            reqmean - The required mean value of the image.
            reqvar  - The required variance of the image.
```
Offsets and rescales image so that nimg has mean reqmean and variance
reqvar.
"""
function normalise(img::Array)
    # Normalise 0 - 1
    n = img .- minimum(img)
    return n = n/maximum(n)
end

# Normalise to desired mean and variance
function normalise(img::Array, reqmean::Real, reqvar::Real)
    n = img .- mean(img)
    n = n/std(img)      # Zero mean, unit std dev
    return n = reqmean .+ n*sqrt(reqvar)
end

# For those who spell normalise with a 'z'
"""
normalize - Normalizes image values to 0-1, or to desired mean and variance
```
Usage 1:      nimg = normalize(img)
```
Offsets and rescales image so that the minimum value is 0
and the maximum value is 1.
```
Usage 2:      nimg = normalize(img, reqmean, reqvar)

Arguments:  img     - A grey-level input image.
            reqmean - The required mean value of the image.
            reqvar  - The required variance of the image.
```
Offsets and rescales image so that nimg has mean reqmean and variance
reqvar.
"""
function normalize(img::Array)
    return normalise(img)
end

function normalize(img::Array, reqmean::Real, reqvar::Real)
    return normalise(img, reqmean, reqvar)
end

#----------------------------------------------------------------------
"""
histtruncate - Truncates ends of an image histogram.

Function truncates a specified percentage of the lower and
upper ends of an image histogram.

This operation allows grey levels to be distributed across
the primary part of the histogram.  This solves the problem
when one has, say, a few very bright values in the image which
have the overall effect of darkening the rest of the image after
rescaling.

```
Usage:
1)   newimg = histtruncate(img, lHistCut, uHistCut)
2)   newimg = histtruncate(img, HistCut)

Arguments:
 Usage 1)
   img         -  Image to be processed.
   lHistCut    -  Percentage of the lower end of the histogram
                  to saturate.
   uHistCut    -  Percentage of the upper end of the histogram
                  to saturate.  If omitted or empty defaults to the value
                  for lHistCut.
 Usage 2)
   HistCut     -  Percentage of upper and lower ends of the histogram to cut.

Returns:
   newimg      -  Image with values clipped at the specified histogram
                  fraction values.  If the input image was colour the
                  lightness values are clipped and stretched to the range
                  0-1.  If the input image is greyscale no stretching is
                  applied. You may want to use normalise() to achieve this.
```
See also: normalise
"""
function  histtruncate(img::Array, lHistCut::Real, uHistCut::Real)
    # July      2001 - Original version
    # February  2012 - Added handling of NaN values in image
    # February  2014 - Code cleanup
    # September 2014 - Default for uHistCut + cleanup

    if lHistCut < 0 || lHistCut > 100 || uHistCut < 0 || uHistCut > 100
	error("Histogram truncation values must be between 0 and 100")
    end

    if ndims(img) > 2
	error("histtruncate only defined for grey scale images")
    end

    newimg = copy(img)
    sortv = sort(newimg[:])   # Generate a sorted array of pixel values.

    # Any NaN values will end up at the end of the sorted list. We
    # need to ignore these.
    N = sum(.!(isnan.(sortv)))  # Number of non NaN values.

    # Compute indicies corresponding to specified upper and lower fractions
    # of the histogram.
    lind = floor(Int, 1 + N*lHistCut/100)
    hind =  ceil(Int, N - N*uHistCut/100)

    low_val  = sortv[lind]
    high_val = sortv[hind]

    # Adjust image
    newimg[newimg .< low_val] .= low_val
    newimg[newimg .> high_val] .= high_val

    return newimg
end

function  histtruncate(img::Array, HistCut::Real)
    return histtruncate(img, HistCut, HistCut)
end

#----------------------------------------------------------------------
"""
sineramp  - Generates sine on a ramp colour map test image

The test image consists of a sine wave superimposed on a ramp function The
amplitude of the sine wave is modulated from its full value at the top of the
image to 0 at the bottom.

The image is useful for evaluating the effectiveness of different colour maps.
Ideally the sine wave pattern should be equally discernible over the full
range of the colour map.  In addition, across the bottom of the image, one
should not see any identifiable features as the underlying signal is a smooth
ramp.  In practice many colour maps have uneven perceptual contrast over their
range and often include 'flat spots' of no perceptual contrast that can hide
significant features.

```
Usage: img = sineramp(sze, amp, wavelen, p)
       img = sineramp()

Arguments:     sze - (rows, cols) specifying size of test image.
                     Defaults to (256 512)  Note the number of columns is
                     nominal and will be ajusted so that there are an
                     integer number of sine wave cycles across the image.
               amp - Amplitude of sine wave. Defaults to 12.5
           wavelen - Wavelength of sine wave in pixels. Defaults to 8.
                 p - Power to which the linear attenuation of amplitude,
                     from top to bottom, is raised.  For no attenuation use
                     p = 0.  For linear attenuation use a value of 1.  For
                     contrast sensitivity experiments use larger values of
                     p.  The default value is 2.
```
The ramp function that the sine wave is superimposed on is adjusted slightly
for each row so that each row of the image spans the full data range of 0 to
255.  Thus using a large sine wave amplitude will result in the ramp at the
top of the test image being reduced relative to the slope of the ramp at
the bottom of the image.

To start with try

```
  > img = sineramp()
```
This is equivalent to

```
  > img = sineramp((256 512), 12.5, 8, 2)
```
View it under 'gray' then try the 'jet', 'hsv', 'hot' etc colour maps.  The
results may cause you some concern!

If you are wishing to evaluate a cyclic colour map, say hsv, it is suggested
that you use the test image generated by circlesineramp().

See source code comments for more details on the default wavelength
and amplitude.

See also: circlesineramp, chirplin, chirpexp, equalisecolourmap, cmap
"""
function sineramp(sze=(256,512), amp=12.5, wavelen=8, p=2)
    #=
    The Default Wavelength:
    The default wavelength is 8 pixels.  On a computer monitor with a nominal
    pixel pitch of 0.25mm this corresponds to a wavelength of 2mm.  With a monitor
    viewing distance of 600mm this corresponds to 0.19 degrees of viewing angle or
    approximately 5.2 cycles per degree.  This falls within the range of spatial
    frequencies (3-7 cycles per degree ) at which most people have maximal
    contrast sensitivity to a sine wave grating (this varies with mean luminance).
    A wavelength of 8 pixels is also sufficient to provide a reasonable discrete
    representation of a sine wave.  The aim is to present a stimulus that is well
    matched to the performance of the human visual system so that what we are
    primarily evaluating is the colour map's perceptual contrast and not the visual
    performance of the viewer.

    The Default Amplitude:
    This is set at 12.5 so that from peak to trough we have a local feature of
    magnitude 25.  This is approximately 10% of the 256 levels in a standard
    colour map. It is not uncommon for colour maps to have perceptual flat spots
    that can hide features of this magnitude.
    =#

    # July  2013  Original version.
    # March 2014  Adjustments to make it better for evaluating cyclic colour maps.
    # June  2014  Default wavelength changed from 10 to 8.

    # ** Should I make this function return UInt8 values ?**

    # Adjust width of image so that we have an integer number of cycles of
    # the sinewave.  This is helps should one be using the test image to
    # evaluate a cyclic colour map.  However you will still see a slight
    # cyclic discontinuity at the top of the image, though this will
    # disappear at the bottom of the test image
    (rows,cols) = sze
    cycles = round(cols/wavelen)
    cols = cycles*wavelen

    # Sine wave
    x = collect(0:cols-1)'
    fx = amp*sin.( 1.0/wavelen * 2*pi*x)

    # Vertical modulating function
    A = (collect((rows-1):-1:0)'/(rows-1)).^float(p)
    img = A'*fx

    # Add ramp
    ramp = [c/(cols-1) for r = 1:rows, c = 0:(cols-1)]
    img = img + ramp*(255.0 - 2*amp)

    # Now normalise each row so that it spans the full data range from 0 to 255.
    # Again, this is important for evaluation of cyclic colour maps though a
    # small cyclic discontinuity will remain at the top of the test image.
    for r = 1:rows
        img[r,:] = normalise(img[r,:])
    end
    img = img * 255.0
    return img
end

#----------------------------------------------------------------------
"""
circlesineramp - Generates a test image for evaluating cyclic colour maps

```
Usage: (img, alpha) = circlesineramp(sze, amp, wavelen, p, hole)
       (img, alpha) = circlesineramp()

Arguments:     sze - Size of test image.  Defaults to 512x512.
               amp - Amplitude of sine wave. Defaults to pi/10
           wavelen - Wavelength of sine wave at half radius of the
                     circular test image. Defaults to 8 pixels.
                 p - Power to which the linear attenuation of amplitude,
                     from outside edge to centre, is raised.  For no
                     attenuation use p = 0.  For linear attenuation use a
                     value of 1.  The default value is 2, quadratic
                     attenuation.
              hole - Boolean flag indicating whether the test image should have
                     a 'hole' in its centre.  The default is true, to have a
                     hole, this removes the distraction of the orientation
                     singularlity at the centre.
Returns:
                im - The test image.
             alpha - Alpha mask matching the regions outside of of the
                     circular test image that are set to NaN.  Used if you
                     want to write an image with these regions transparent.
```
The test image is a circular pattern consistsing of a sine wave superimposed
on a spiral ramp function.  The spiral ramp starts at a value of 0 pointing
right, increasing anti-clockwise to a value of 2*pi as it completes the full
circle. This gives a 2*pi discontinuity on the right side of the image.  The
amplitude of the superimposed sine wave is modulated from its full value at
the outside of the circular pattern to 0 at the centre.  The default sine wave
amplitude of pi/10 means that the overall size of the sine wave from peak to
trough represents 2*(pi/10)/(2*pi) = 10% of the total spiral ramp of 2*pi.  If
you are testing your colour map over a cycle of pi you should use amp = pi/20
to obtain an equivalent ratio of sine wave to circular ramp.

The image is designed for evaluating the effectiveness of cyclic colour maps.
It is the cyclic companion to sineramp().  Ideally the sine wave pattern should
be equally discernible over all angles around the test image.  In practice
many colourmaps have uneven perceptual contrast over their range and often
include 'flat spots' of no perceptual contrast that can hide significant
features.  Try a HSV colour map.

Ideally the test image should be rendered with a cyclic colour map using
showangularim() though, in this case, rendering the image with SHOW or IMAGESC
will also be fine because all image values lie within, and use the full range
of, 0-2*pi.  However, in general, default display methods typically do not
respect data values directly and can perform inappropriate offsetting and
normalisation of the angular data before display and rendering with a colour
map.

For angular data to be rendered correctly it is important that the data values
are respected so that data values are correctly assigned to specific entries
in a cyclic colour map.  The assignment of values to colours also depends on
whether the data is cyclic over pi, or 2*pi.  SHOWANGULARIM supports this.

See also: applycycliccolourmap, sineramp, chirplin, chirpexp, equalisecolourmap, cmap
"""
function circlesineramp(sze=512, amp=pi/10, wavelen=8, p=2, hole=true)
    # September 2014  Original version.
    # October   2014  Number of cycles calculated from wave length rather than
    #                 being specified directly.

    # Set values for inner and outer radii of test pattern
    maxr = sze/2 * 0.9
    if hole
        minr = 0.15*sze
    else
        minr = 0
    end

    # Determine number of cycles to achieve desired wavelength at half radius
    meanr = (maxr + minr)/2
    circum = 2*pi*meanr
    cycles = round(circum/wavelen)

    # Angles are +ve anticlockwise and mod 2*pi
    theta = [mod(atan(-y,x), 2*pi) for y = -sze/2:sze/2, x = -sze/2:sze/2 ]
    rad = [sqrt(x^2 + y^2) for y = -sze/2:sze/2, x = -sze/2:sze/2 ]

    # Normalise radius so that it varies 0-1 over minr to maxr
    rad = (rad.-minr)/(maxr-minr)

    # Form the image
    img = amp*rad.^float(p) .* sin.(cycles*theta) + theta

    # Ensure all values are within 0-2*pi so that a simple default display
    # with a cyclic colour map will render the image correctly.
    img = mod.(img, 2*pi)

    # 'Nanify' values outside normalised radius values of 0-1
    alpha = ones(size(img))
    img[rad .> 1] .= NaN
    alpha[rad .> 1] .= 0

    if hole
        img[rad .< 0] .= NaN
        alpha[rad .< 0] .= 0
    end

   return img, alpha
end

#---------------------------------------------------------------------


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

mutable struct HardwareProfile <: SwaggerModel
    vmSize::Any # spec type: Union{ Nothing, String } # spec name: vmSize

    function HardwareProfile(;vmSize=nothing)
        o = new()
        validate_property(HardwareProfile, Symbol("vmSize"), vmSize)
        setfield!(o, Symbol("vmSize"), vmSize)
        o
    end
end # type HardwareProfile

const _property_map_HardwareProfile = Dict{Symbol,Symbol}(Symbol("vmSize")=>Symbol("vmSize"))
const _property_types_HardwareProfile = Dict{Symbol,String}(Symbol("vmSize")=>"String")
Base.propertynames(::Type{ HardwareProfile }) = collect(keys(_property_map_HardwareProfile))
Swagger.property_type(::Type{ HardwareProfile }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_HardwareProfile[name]))}
Swagger.field_name(::Type{ HardwareProfile }, property_name::Symbol) =  _property_map_HardwareProfile[property_name]

const _allowed_HardwareProfile_vmSize = ["Basic_A0", "Basic_A1", "Basic_A2", "Basic_A3", "Basic_A4", "Standard_A0", "Standard_A1", "Standard_A2", "Standard_A3", "Standard_A4", "Standard_A5", "Standard_A6", "Standard_A7", "Standard_A8", "Standard_A9", "Standard_A10", "Standard_A11", "Standard_A1_v2", "Standard_A2_v2", "Standard_A4_v2", "Standard_A8_v2", "Standard_A2m_v2", "Standard_A4m_v2", "Standard_A8m_v2", "Standard_D1", "Standard_D2", "Standard_D3", "Standard_D4", "Standard_D11", "Standard_D12", "Standard_D13", "Standard_D14", "Standard_D1_v2", "Standard_D2_v2", "Standard_D3_v2", "Standard_D4_v2", "Standard_D5_v2", "Standard_D11_v2", "Standard_D12_v2", "Standard_D13_v2", "Standard_D14_v2", "Standard_D15_v2", "Standard_DS1", "Standard_DS2", "Standard_DS3", "Standard_DS4", "Standard_DS11", "Standard_DS12", "Standard_DS13", "Standard_DS14", "Standard_DS1_v2", "Standard_DS2_v2", "Standard_DS3_v2", "Standard_DS4_v2", "Standard_DS5_v2", "Standard_DS11_v2", "Standard_DS12_v2", "Standard_DS13_v2", "Standard_DS14_v2", "Standard_DS15_v2", "Standard_F1", "Standard_F2", "Standard_F4", "Standard_F8", "Standard_F16", "Standard_F1s", "Standard_F2s", "Standard_F4s", "Standard_F8s", "Standard_F16s", "Standard_G1", "Standard_G2", "Standard_G3", "Standard_G4", "Standard_G5", "Standard_GS1", "Standard_GS2", "Standard_GS3", "Standard_GS4", "Standard_GS5", "Standard_H8", "Standard_H16", "Standard_H8m", "Standard_H16m", "Standard_H16r", "Standard_H16mr", "Standard_L4s", "Standard_L8s", "Standard_L16s", "Standard_L32s", "Standard_NC6", "Standard_NC12", "Standard_NC24", "Standard_NC24r", "Standard_NV6", "Standard_NV12", "Standard_NV24"]

function check_required(o::HardwareProfile)
    true
end

function validate_property(::Type{ HardwareProfile }, name::Symbol, val)
    if name === Symbol("vmSize")
        Swagger.validate_param(name, "HardwareProfile", :enum, val, _allowed_HardwareProfile_vmSize)
    end
end


text:
using Base.Iterators
using CVChannel
using LinearAlgebra
using QBase
using Random
using Test

"""
In a previous note, Marius Junge described a channel that has a super-multiplicative
communication value (CV). This channel maps a 4-dimension Hilbert
space to a 5-dimension Hilbert space.
In this script, we first certify the CV of the singular use of this channel to be 2.
Then, we demonstrate using the see-saw method that the channel can achieve the
theoretical maximum CV of 5.
"""

"""
The channel is described by 5 operators which act upon a quantum state ρ to construct
the evolved state. Note that these operators do not for a typical kraus channel as
they are not complete.
"""
function marius_example_channel_operators()
    k1 = kron(σx, σI)
    k2 = kron(σy, σI)
    k3 = kron(σz, σx)
    k4 = kron(σz, σy)
    k5 = kron(σz, σz)

    [k1,k2,k3,k4,k5]
end

"""
The singular channel is implemented with the following method. The input `ρ`
must be an 4x4 matrix.
"""
function marius_example_channel(ρ :: AbstractMatrix)
    c = marius_example_channel_operators()
    basis = computational_basis_vectors(5)

     return sum( r -> sum( s -> tr(c[r]'*ρ*c[s])*basis[r]*basis[s]', 1:5), 1:5)/5
end

"""
The product of two instances of the channel is considered. The input `ρ` must be
a 16x16 matrix.
"""
function par_marius_example_channel(ρ :: AbstractMatrix)
    k_ops = marius_example_channel_operators()
    k_prod_ops = collect(flatten(map(k_a -> map(k_b -> kron(k_a, k_b), k_ops), k_ops)))
    basis = computational_basis_vectors(25)

    return sum( r -> sum( s -> tr(k_prod_ops[r]'*ρ*k_prod_ops[s])*basis[r]*basis[s]', 1:25), 1:25)/25
end

"""
Claim: the communication value of a single channel use of `marius_example_channel`
does not exceed 2.

The following tests certify this communication value using the primal and dual of
the PPT relaxation. Then we show that the PPT outer approximation is tight with
the CV using the see-saw method.
"""

println("\nVerifying communication value of a single channel use")

@time @testset "communication value of single channel use" begin

    choi_chan = Choi(marius_example_channel, 4, 5)
    kraus_ops = map(i -> reshape(choi_chan.JN[:,i],(5,4)) , 1:20)
    @test sum(k -> k' * k , kraus_ops) ≈ I
    @test choi(kraus_ops) ≈ choi_chan.JN

    @testset "PPT relaxation CV" begin
        cv_primal, = pptCV(choi_chan)
        cv_dual, = pptCV(choi_chan, :dual)

        @test cv_primal ≈ 2 atol=1e-6
        @test cv_dual ≈ 2 atol=1e-6
    end

    @testset "see-saw optimziation" begin
        Random.seed!(42)
        init_states = haarStates(4,4)
        cv_tuple4, = seesawCV(init_states, kraus_ops, 5)

        @test cv_tuple4[1] ≈ 2 atol=1e-3
        @test all(ρ -> is_density_matrix(ρ, atol=1e-6), cv_tuple4[2])
        @test is_povm(cv_tuple4[3], atol=1e-6)

        init_states = haarStates(8,4)
        cv_tuple8, = seesawCV(init_states, kraus_ops, 5)

        @test cv_tuple8[1] ≈ 2 atol=1e-4
        @test all(ρ -> is_density_matrix(ρ, atol=1e-6), cv_tuple8[2])
        @test is_povm(cv_tuple8[3], atol=2e-6)

        init_states = haarStates(16,4)
        cv_tuple16, = seesawCV(init_states, kraus_ops, 5)

        @test cv_tuple16[1] ≈ 2 atol=2e-6
        @test all(ρ -> is_density_matrix(ρ, atol=2e-6), cv_tuple16[2])
        @test is_povm(cv_tuple16[3], atol=1e-6)
    end
end

"""
Claim: The product channel `marius_example_channel_prod` has a communication value
of 5.

The singular use of the channel is certified to be 2. We showed this above using
the primal and dual form of the PPT relaxation to find a communication value of 2
and this was demonstrated to be tight with the CV using the see-saw method.
Hence any communication value found to be greater than 4 is a expression of
super-multiplicativity. We demonstrate that the see-saw method can find the
theoretical maximum which is known to be 5.
"""

println("\nVerifying super-multiplivity of communication value of the product channel...")

@time @testset "communication value of parallel channel uses" begin

    par_choi_chan = Choi(par_marius_example_channel, 16, 25)
    par_kraus_ops = map(i -> reshape(par_choi_chan.JN[:,i],(25,16)) , 1:400)
    @test sum(k -> k' * k , par_kraus_ops) ≈ I
    @test choi(par_kraus_ops) ≈ par_choi_chan.JN

    @testset "see-saw verification of super-multiplicativity" begin
        println("performing see-saw optimization of parallel channel")
        Random.seed!(314)
        par_init_states = haarStates(32,16)
        cv_tuple32, = seesawCV(par_init_states, par_kraus_ops, 10, verbose=true)

        @test cv_tuple32[1] ≈ 5 atol=3e-2
        @test all(ρ -> is_density_matrix(ρ, atol=1e-6), cv_tuple32[2])
        @test is_povm(cv_tuple32[3], atol=1e-5)
    end
end

max_forks_repo_name: ChitambarLab/cv-channel


text:
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.0.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.0.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.0.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.0.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.2.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.2.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.2.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.2.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.0.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.0.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.2.1-DEV") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.0.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.0.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.2.1-DEV") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.2.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.2.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.2.1-DEV") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.2.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.2.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.2.1-DEV") == v"1.2.1"

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.0.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.0.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"0.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0-DEV", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.0.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.0.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"0.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3-DEV", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.2.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.2.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"0.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0-DEV", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.2.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.2.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"0.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3-DEV", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.0.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.0.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"1.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0-DEV", v"2.2.1") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.0.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.0.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"1.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3-DEV", v"2.2.1") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.2.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.2.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"1.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0-DEV", v"2.2.1") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.2.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.2.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"1.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3-DEV", v"2.2.1") == v"1.2.1"

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

@test VersionVigilante._calculate_increment(v"0.0.0", v"0.0.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.0.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.0.3", v"0.0.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.0.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.0", v"0.2.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.2.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.3", v"0.2.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.2.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.0.0-DEV") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.0.1-DEV") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.1.0-DEV") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.1.1-DEV") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.2.0-DEV") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.2.1-DEV") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"1.0.0", v"1.0.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.0.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.2.1-DEV") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.0.3", v"1.0.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.0.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.1.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.1.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.2.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.2.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.2.1-DEV") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.0", v"1.2.1-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.2.2-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.2.1-DEV") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.3", v"1.2.4-DEV") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.2.5-DEV") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.3.0-DEV") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.3.1-DEV") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.4.0-DEV") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.4.1-DEV") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.0.0-DEV") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.0.1-DEV") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.1.0-DEV") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.1.1-DEV") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.2.0-DEV") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.2.1-DEV") == v"1.2.1"

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

@test VersionVigilante._calculate_increment(v"0.0.0", v"0.0.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.0.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"0.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.0", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.0.3", v"0.0.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.0.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"0.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.0.3", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.0", v"0.2.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.2.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"0.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.0", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"0.2.3", v"0.2.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.2.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"0.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"1.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.0.0") == v"2.0.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.0.1") == v"2.0.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.1.0") == v"2.1.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.1.1") == v"2.1.1"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.2.0") == v"2.2.0"
@test VersionVigilante._calculate_increment(v"0.2.3", v"2.2.1") == v"2.2.1"

@test VersionVigilante._calculate_increment(v"1.0.0", v"1.0.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.0.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"1.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.0", v"2.2.1") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.0.3", v"1.0.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.0.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.1.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.1.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.2.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"1.2.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.0.3", v"2.2.1") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.0", v"1.2.1") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.2.2") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"1.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.0", v"2.2.1") == v"1.2.1"

@test VersionVigilante._calculate_increment(v"1.2.3", v"1.2.4") == v"0.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.2.5") == v"0.0.2"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.3.0") == v"0.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.3.1") == v"0.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.4.0") == v"0.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"1.4.1") == v"0.2.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.0.0") == v"1.0.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.0.1") == v"1.0.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.1.0") == v"1.1.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.1.1") == v"1.1.1"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.2.0") == v"1.2.0"
@test VersionVigilante._calculate_increment(v"1.2.3", v"2.2.1") == v"1.2.1"


text:
using OrdinaryDiffEq, Test, Random, LinearAlgebra, LinearSolve
Random.seed!(123)

A = 0.01*rand(3, 3)
rn = (du, u, p, t) -> begin
    mul!(du, A, u)
end
u0 = rand(3)
prob = ODEProblem(rn, u0, (0, 50.))

function precsl(W,du,u,p,t,newW,Plprev,Prprev,solverdata)
  if newW === nothing || newW
    Pl = lu(convert(AbstractMatrix,W))
  else
    Pl = Plprev
  end
  Pl,nothing
end

function precsr(W,du,u,p,t,newW,Plprev,Prprev,solverdata)
  if newW === nothing || newW
    Pr = lu(convert(AbstractMatrix,W))
  else
    Pr = Prprev
  end
  nothing,Pr
end

function precslr(W,du,u,p,t,newW,Plprev,Prprev,solverdata)
  if newW === nothing || newW
    Pr = lu(convert(AbstractMatrix,W))
  else
    Pr = Prprev
  end
  Pr,Pr
end

sol = @test_nowarn solve(prob, TRBDF2(autodiff=false));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=IterativeSolversJL_GMRES()));
@test length(sol.t) < 20
solref = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=IterativeSolversJL_GMRES(), smooth_est=false));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=IterativeSolversJL_GMRES(), precs=precsl, smooth_est=false, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=IterativeSolversJL_GMRES(), precs=precsr, smooth_est=false, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=IterativeSolversJL_GMRES(), precs=precslr, smooth_est=false, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, QNDF(autodiff=false, linsolve=IterativeSolversJL_GMRES(), concrete_jac = true));
@test length(sol.t) < 25
sol = @test_nowarn solve(prob, Rosenbrock23(autodiff=false, linsolve=IterativeSolversJL_GMRES(), precs=precslr, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, Rodas4(autodiff=false, linsolve=IterativeSolversJL_GMRES(), precs=precslr, concrete_jac = true));
@test length(sol.t) < 20

sol = @test_nowarn solve(prob, TRBDF2(autodiff=false));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=KrylovJL_GMRES()));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=KrylovJL_GMRES(), smooth_est=false));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=KrylovJL_GMRES(), precs=precsl, smooth_est=false, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=KrylovJL_GMRES(), precs=precsr, smooth_est=false, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, TRBDF2(autodiff=false, linsolve=KrylovJL_GMRES(), precs=precslr, smooth_est=false, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, QNDF(autodiff=false, linsolve=KrylovJL_GMRES(), concrete_jac = true));
@test length(sol.t) < 25
sol = @test_nowarn solve(prob, Rosenbrock23(autodiff=false, linsolve=KrylovJL_GMRES(), precs=precslr, concrete_jac = true));
@test length(sol.t) < 20
sol = @test_nowarn solve(prob, Rodas4(autodiff=false, linsolve=KrylovJL_GMRES(), precs=precslr, concrete_jac = true));
@test length(sol.t) < 20