text:
#=
Copyright (c) 2015, Intel Corporation

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Intel Corporation nor the names of its contributors
      may be used to endorse or promote products derived from this software
      without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=#

# This file is used for preventing regressions and keeping the quality of the
# repository higher every checkin.
# For the module you write, please write as many unit test cases as possible, and
# add the corresponding entries for them -- so that your code will not be accidently
# affected by other people's checkins!

@doc """"
A pattern to match with a test's output. The pattern is a regular expression.
The comment explains the pattern, e.g. what the pattern is supposed to do, as
a friendly message when the pattern does not match.
"""
immutable TestPattern
    pattern :: Regex
    comment :: AbstractString
end

@doc """"
A pattern not to match with a test's output. The pattern is a regular expression.
The comment explains the pattern, e.g. what the pattern is supposed to do, as
a friendly message when the pattern does match.
"""
immutable AntiTestPattern
    pattern :: Regex
    comment :: AbstractString
end

immutable Test
    name     :: AbstractString
    command  :: AbstractString
    patterns :: Vector{Union{TestPattern, AntiTestPattern}}
end

root_path       = joinpath(dirname(@__FILE__), "../..")
load_path       = joinpath(root_path, "deps")
julia_command   = joinpath(root_path, "deps", "julia")

# The following patterns often contains "(.|n)*?something". This is to let
# pcregrep (if USE_PCREGREP_REGEX_MATCH is true) match immediately when
# something appears. Otherwise, it will maximize the match and thus (.|n)* can
# match the whole file, causing segmentation fault, etc.

const exception_pattern = AntiTestPattern(
    r"Exception!",
    "Test if an exception has been thrown in sparse accelerator"
)

const sanity_test1 = Test(
    "sanity-test1",
    "sanity-test1.jl",
    [
        TestPattern(r" {4,4}1 tab",
                     "Test tabbed output facility: 1 tab."
        ),
        TestPattern(r" {8,8}2 tabs",
                     "Test tabbed output facility: 2 tabs."
        ),
        TestPattern(r" {12,12}3 tabs",
                     "Test tabbed output facility: 3 tabs."
        ),
        exception_pattern
    ]
)

const sanity_test2 = Test(
    "sanity-test2",
    "sanity-test2.jl",
    [
        TestPattern(r"I do nothing!",
                     "Test if optimization framework adds a new optimization pass."
        ),
        exception_pattern
    ]
)

const sanity_test3 = Test(
    "sanity-test3",
    "sanity-test3.jl",
    [
        TestPattern(r"New AST:(.|\n)*?return A \* x",
                     "Test if optimization framework invokes Sparso to generate a new AST."
        ),
        exception_pattern
    ]
)

const spmv_sanity_test1 = Test(
    "spmv-sanity-test1",
    "spmv-sanity-test1.jl ../matrices/tiny-diag.mtx",
    [
        TestPattern(r"Original sum of p=20.169999999999995",
                     "Test original code"
        ),
        TestPattern(r"Manual sum of p=20.169999999999995",
                     "Test code manually replaced with SpMV!"
        ),
        exception_pattern
    ]
)

const CG_MATRIX = "../matrices/bcsstk14.mtx"

const context_test1 = Test(
    "context-test1",
    string("context-test1.jl ", CG_MATRIX),
    [
        TestPattern(r"Original k=208",
                     "Test iterations"
        ),
        TestPattern(r"Original rel_err=8.89\d*e-8",
                     "Test rel_err"
        ),
        TestPattern(r"Constant structures discovered:\n.*\[:A,:L,:U\]",
                     "Test constant structures"
        ),
        TestPattern(r"Structure symmetry discovered:\n.*\[:A\]",
                     "Test structure symmetry"
        ),
        TestPattern(r"L is lower of A",
                     "Test L and A"
        ),
        TestPattern(r"U is upper of A",
                     "Test U and A"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobA.* = \(Sparso.new_matrix_knob\)\(:A,true,true,true,true,false,false\)",
                     "Test if mknobA is generated and is constant valued and constant structured"
        ),
        TestPattern(r"New AST:(.|\n)*?add_mknob_to_fknob\)\(.*mknobA.*,..*fknob.*\)",
                     "Test if mknobA is added to a function knob (for SpMV)"
        ),
        TestPattern(r"New AST:(.|\n)*?Ap = \(Sparso.SpMV\)\(1,A.*,p.*,.*fknob.*\)",
                     "Test if Ap = A * p has been replaced with SpMV with context info"
        ),
        TestPattern(r"New AST:(.|\n)*?set_reordering_decision_maker",
                     "Test reordering"
        ),
        TestPattern(r"\(Sparso.reordering\)\(__fknob\d*__,__reordering_status\d*__,A,Sparso.ROW_PERM,Sparso.ROW_INV_PERM,__mknobA\d*__,U,Sparso.ROW_PERM,Sparso.ROW_INV_PERM,__mknobU\d*__,:__delimitor__,p,Sparso.ROW_PERM,r,Sparso.ROW_PERM,x,Sparso.ROW_PERM\)",
                     "Test reordering"
        ),
        TestPattern(r"reverse_reordering\)\(__reordering_status\d*__,:__delimitor__,x,Sparso.ROW_PERM\)",
                     "Test reordering"
        ),
        TestPattern(r"Accelerated k=208",
                     "Test iterations"
        ),
        TestPattern(r"Accelerated rel_err=8.89\d*e-8",
                     "Test rel_err"
        ),
        exception_pattern
    ]
)

const context_test2 = Test(
    "context-test2",
    string("context-test2.jl ", CG_MATRIX, " ", CG_MATRIX),
    [
        TestPattern(r"Original k=208",
                     "Test iterations"
        ),
        TestPattern(r"Original rel_err=8.89\d*e-8",
                     "Test rel_err"
        ),
        TestPattern(r"Manual_context_no_reorder sum of x=40.11\d*",
                     "Test sum of pcg_symgs"
        ),
        TestPattern(r"Manual_context_no_reorder k=208",
                     "Test iterations"
        ),
        TestPattern(r"Manual_context_no_reorder rel_err=8.89\d*e-8",
                     "Test rel_err"
        ),
        TestPattern(r"Manual_context k=208",
                     "Test iterations"
        ),
        TestPattern(r"Manual_context rel_err=8.89\d*e-8",
                     "Test rel_err"
        ),
        exception_pattern
    ]
)

const context_test2_ilu0 = Test(
    "context-test2-ilu0",
    string("context-test2-ilu0.jl  ../matrices/lap3d_4x4x4.mtx"),
    [
        TestPattern(r"Original:(.|\n)*?k=5(.|\n)*?rel_err=4.398690\d*e-9",
                     "Test pcg_symgs"
        ),
        TestPattern(r"With manual context-sensitive optimization without reordering:(.|\n)*?k=5(.|\n)*?rel_err=4.398690\d*e-9",
                     "Test pcg_symgs with contextopt but without reordering"
        ),
        TestPattern(r"With manual context-sensitive optimization:(.|\n)*?k=5(.|\n)*?rel_err=4.398690\d*e-9",
                     "Test pcg_symgs_with_context_opt"
        ),
        exception_pattern
    ]
)

const context_test2_without_reordering = Test(
    "context-test2-without-reordering",
    string("context-test2-without-reordering.jl ", CG_MATRIX),
    [
        TestPattern(r"Original:(.|\n)*?sum of x=40.11\d*(.|\n)*?rel_err=8.89\d*e-8",
                     "Test pcg_symgs"
        ),
        TestPattern(r"With manual context-sensitive optimization:(.|\n)*?sum of x=40.11\d*(.|\n)*?rel_err=8.89\d*e-8",
                     "Test pcg_symgs_with_context_opt"
        ),
        exception_pattern
    ]
)

const context_test3 = Test(
    "context-test3",
    "context-test3.jl ipm/mps/osa-14",
    [
        TestPattern(r"New AST:(.|\n)*?__AT__ = \(Main.ctranspose\)\(A",
                     "Test if accelerated ipm-ref generates AT"
        ),
        TestPattern(r"New AST:(.|\n)*?mknob__AT__.*new_matrix_knob",
                     "Test if accelerated ipm-ref generates matrix knob for AT"
        ),
#        TestPattern(r"New AST:(.|\n)*?mknob__AT__.*new_matrix_knob\)\(__AT__",
#                     "Test if accelerated ipm-ref generates matrix knob for AT"
#        ),
        TestPattern(r"New AST:(.|\n)*?mknobD.*new_matrix_knob",
                     "Test if accelerated ipm-ref generates matrix knob for D"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobA.*new_matrix_knob",
                     "Test if accelerated ipm-ref generates matrix knob for A"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobB.*new_matrix_knob",
                     "Test if accelerated ipm-ref generates matrix knob for B"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobR.*new_matrix_knob",
                     "Test if accelerated ipm-ref generates matrix knob for R"
        ),
        TestPattern(r"New AST:(.|\n)*?new_function_knob(.|\n)*?new_function_knob(.|\n)*?new_function_knob",
                     "Test if accelerated ipm-ref generates function knobs"
        ),
        TestPattern(r"New AST:(.|\n)*?B = .*\(Sparso.ADB\)\(A.*,D.*,__AT__.*,__fknob\d*?__",
                     "Test if accelerated ipm-ref generates ADB"
        ),
        TestPattern(r"New AST:(.|\n)*?B = .*\(Sparso.ADB\).*\n.*propagate_matrix_info.*mknobB.*mknobExpr",
                     "Test if accelerated ipm-ref generates propagate_matrix_info after B = ADB"
        ),
        TestPattern(r"New AST:(.|\n)*?R = .*\(Sparso.cholfact_int32\)\(B.*,__fknob\d*?__",
                     "Test if accelerated ipm-ref generates cholfact_int32"
        ),
        TestPattern(r"New AST:(.|\n)*?dy = .*\(Sparso.cholfact_inverse_divide\)\(R.*,t2.*,__fknob\d*?__",
                     "Test if accelerated ipm-ref generates cholfact_inverse_divide"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.set_derivative\)\(.*mknobA.*,Sparso.DERIVATIVE_TYPE_TRANSPOSE,.*mknob__AT.*\)",
                     "Test if accelerated ipm-ref generates a derivative between A and A'"
        ),
        # TODO: enable these patterns
#        TestPattern(r"New AST:(.|\n)*?Rd = .*\(Sparso.SpMV\)\(1,__AT__,y,1,s-p,fknob_spmv.*\)",
#                     "Test call replacement. Currently cannot match as we need to handle AT specially."
#        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Rp,1,A,x,-1,b,0,.*?fknob.*?\)",
                     "Test call replacement."
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.element_wise_multiply!\)\(Rc,x,s\)",
                     "Test call replacement."
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.WAXPB!\)\(Rc,1,Rc,-\(\(Main.min\)\(0.1,100 \* mu.*?\).*? \* mu.*?\)",
                     "Test call replacement."
        ),
        #TestPattern(r"Original sum of x=715375.98850000",
                     #"Test original ipm-ref"
        #),
        TestPattern(r"Original iter 26, resid =  3.93e-15",
                     "Test original ipm-ref"
        ),
        #TestPattern(r"Accelerated sum of x=715375.98850000",
                     #"Test ipm-ref with context-sensitve optimization"
        #),
        TestPattern(r"Accelerated iter 26, resid =  3.93e-15",
                     "Test ipm-ref with context-sensitve optimization"
        ),
        exception_pattern
    ]
)

const context_test4 = Test(
    "context-test4",
    "context-test4.jl ipm/mps/osa-14",
    [
        TestPattern(r"Original iter 26, resid =  3.93e-15",
                     "Test original ipm-ref"
        ),
        TestPattern(r"Manual_context iter 26, resid =  3.93e-15",
                     "Test ipm-ref with context-sensitve optimization"
        ),
        exception_pattern
    ]
)

const context_test5 = Test(
    "context-test5",
    "context-test5.jl ../matrices/lap3d_4x4x4.mtx",
    [
        TestPattern(r"Original k=5",
                     "Test original pcg_symgs_ilu0 "
        ),
        TestPattern(r"Original rel_err=4.398690\d*e-9",
                     "Test original pcg_symgs_ilu0 "
        ),
        TestPattern(r"Accelerated k=5",
                     "Test iterations"
        ),
        TestPattern(r"Accelerated rel_err=4.398690\d*e-9",
                     "Test rel_err"
        ),
        TestPattern(r"Constant structures discovered:\n.*\[:A,:L,:U\]",
                     "Test constant structures"
        ),
        TestPattern(r"Structure symmetry discovered:\n.*\[:A\]",
                     "Test structure symmetry"
        ),
        TestPattern(r"L is lower of A",
                     "Test L and A"
        ),
        TestPattern(r"U is upper of A",
                     "Test U and A"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobA.* = \(Sparso.new_matrix_knob\)\(:A,true,true,true,true,false,false\)",
                     "Test if mknobA is generated and is constant valued, constant structured, symmetric valued and structured"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobL.* = \(Sparso.new_matrix_knob\)\(:L,true,true,false,false,false,false\)",
                     "Test if mknobL is generated and is constant valued and constant structured"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobU.* = \(Sparso.new_matrix_knob\)\(:U,true,true,false,false,false,false\)",
                     "Test if mknobL is generated and is constant valued and constant structured"
        ),
        TestPattern(r"New AST:(.|\n)*?set_derivative\)\(.*?mknobL.*?,Sparso.DERIVATIVE_TYPE_SYMMETRIC,.*?mknobA.*?\)",
                    "Test if L is found as part of A"
        ),
        TestPattern(r"New AST:(.|\n)*?set_derivative\)\(.*?mknobU.*?,Sparso.DERIVATIVE_TYPE_SYMMETRIC,.*?mknobA.*?\)",
                    "Test if U is found as part of A"
        ),
        TestPattern(r"New AST:(.|\n)*?add_mknob_to_fknob\)\(.*mknobA.*,..*fknob.*\)",
                     "Test if mknobA is added to a function knob (for SpMV)"
        ),
#        TestPattern(r"New AST:(.|\n)*?Ap = \(Sparso.SpMV\)\(1,A,p,.*fknob.*\)",
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Ap,A,p,__fknob\d*?__\)",
                     "Test if Ap = A * p has been replaced with SpMV with context info"
        ),
        TestPattern(r"New AST:(.|\n)*?set_reordering_decision_maker",
                     "Test reordering"
        ),
#        TestPattern(r"New AST:(.|\n)*?Sparso.reordering\)\(__fknob\d*?__,##reordering_status#\d*?,(U,Sparso.ROW_PERM,Sparso.ROW_INV_PERM,|A,Sparso.ROW_PERM,Sparso.ROW_INV_PERM,){2,2}:__delimitor__,(r,Sparso.ROW_PERM,?|p,Sparso.ROW_PERM,?|x,Sparso.ROW_PERM,?){3,3}\)",
        TestPattern( r"New AST:(.|\n)*?Sparso.reordering\)\(__fknob\d*?__,__reordering_status\d*?__,(U,Sparso.ROW_PERM,Sparso.ROW_INV_PERM,__mknobU\d*?__,|A,Sparso.ROW_PERM,Sparso.ROW_INV_PERM,__mknobA\d*?__,){2,2}:__delimitor__,(r,Sparso.ROW_PERM,?|p,Sparso.ROW_PERM,?|x,Sparso.ROW_PERM,?|Ap,Sparso.ROW_PERM,?){4,4}\)",
                      "Test reordering"
        ),
        TestPattern(r"New AST:(.|\n)*?reverse_reordering\)\(__reordering_status\d*?__,:__delimitor__,x,Sparso.ROW_PERM\)",
                     "Test reordering"
        ),
        TestPattern(r"New AST:(.|\n)*?r = b - \(Sparso.SpMV\)\(A,x\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?normr0 = .*Sparso.norm\)\(r.*\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?rz = .*Sparso.dot\)\(r.*,z.*\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?alpha = old_rz.*?/.*?Sparso.dot\)\(p.*?,Ap.*?\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.WAXPBY!\)\(x,1,x.*?,alpha.*?,p.*?\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.WAXPBY!\)\(r,1,r.*?,-alpha.*?,Ap.*?\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?rel_err = .*?Sparso.norm\)\(r.*?\).*?/ normr0",
                     "Test call replacement"
        ),
# TODO: enable this test.
#        TestPattern(r"New AST:(.|\n)*?Sparso,:copy!\)\(z.*?,r.*?\)",
#                     "Test call replacement"
#        )
        TestPattern(r"New AST:(.|\n)*?Sparso.fwdTriSolve!\)\(L,z,.*?fknob.*?\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.bwdTriSolve!\)\(U,z,.*?fknob.*?\)",
                     "Test call replacement"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.WAXPBY!\)\(p,1,z.*?,beta.*?,p.*?\)",
                     "Test call replacement"
        ),
        exception_pattern
    ]
)

const pagerank_test1 = Test(
    "pagerank-test1",
    "pagerank.jl  ../matrices/hmatrix.1024.mtx",
    [
        TestPattern(r"Original:(.|\n)*?\s*error = 1.53\d*e-8",
                     "Test original pagerank"
        ),
        TestPattern(r"Accelerated:(.|\n)*?\s*error = 1.53\d*e-8",
                     "Test pagerank with reordering"
        ),
        TestPattern(r"New AST:(.|\n)*?set_reordering_decision_maker",
                     "Test pagerank with reordering"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Ap,1 - r.*?,A.*?,p.*?,0,p.*?,r.*?,d_inv.*?,__fknob\d*?__\)",
                     "Test pagerank with reordering"
        ),
        TestPattern(r"reverse_reordering\)\(__reordering_status\d*?__,:__delimitor__,p,Sparso.ROW_PERM\)",
                     "Test pagerank with reordering"
        ),
        TestPattern(r"err = .*?\(Sparso.norm\)\(Ap.*? - p.*?\).*? / .*?\(Sparso.norm\)\(p.*?\)",
                     "Test pagerank if call replacement of norm happens"
        ),
        exception_pattern
    ]
)

const cosp2_test1 = Test(
    "cosp2-test1",
    "cosp2.jl ../matrices/hmatrix.512.mtx",
    [
        TestPattern(r"Original:\nX sum = 6106.4049\d*, max = 1.2808\d*\nNumber of iterations = 25(.|\n)*?End original.",
                     "Test original"
        ),
        #TestPattern(r"CoSP2_call_replacement:\nX sum = 6106.4049\d*, max = 1.2808\d*\nNumber of iterations = 25(.|\n)*?End CoSP2_call_replacement.",
        #             "Test CoSP2_call_replacement"
        #),
        #TestPattern(r"CoSP2_call_replacement_and_context_opt:\nX sum = 6106.4049\d*, max = 1.2808\d*\nNumber of iterations = 25(.|\n)*?End CoSP2_call_replacement_and_context_opt.",
        #             "Test CoSP2_call_replacement_and_context_opt"
        #),
        TestPattern(r"New AST:(.|\n)*?mknobX.*? = \(Sparso.new_matrix_knob\)\(:X,false,.*?,true,true,false,false\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.add_mknob_to_fknob\)\(.*?mknobX.*?,.*?fknob.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?trX = \(Sparso.trace\)\(X.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?X2 = \(Sparso.SpSquareWithEps\)\(X.*?,eps.*?,.*?fknob.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?trX2 = \(Sparso.trace\)\(X2.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?X = \(Sparso.SpAdd\)\(2,X.*?,-1,X2.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?X sum = 6106.4049\d*, max = 1.2808\d*\nNumber of iterations = 25(.|\n)*?End accelerated",
                     "Test accelerated"
        ),
        exception_pattern
    ]
)

#const MTX_covtype = "../matrices/covtype.mtx"

if false
const lbfgs_test1 = Test(
    "lbfgs-test1",
    "lbfgs.jl $MTX_covtype",
    [
        TestPattern(r"Original L-BFGS:      32 iterations f = 0.00000000004134",
                     "Test original"
        ),
        TestPattern(r"Opt L-BFGS:      32 iterations f = 0.00000000004134",
                     "Test optimized version"
        ),
        TestPattern(r"Opt_with_reordering L-BFGS:      33 iterations f = 0.0000000000",
                     "Test Opt_with_reordering"
        ),
        TestPattern(r"Accelerated L-BFGS:      3[345] iterations f = 0.0000000",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobXt.*? = \(Sparso.new_matrix_knob\)\(:Xt,true,true,false,false,false,false\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobX.*? = \(Sparso.new_matrix_knob\)\(:X,true,true,false,false,false,false\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.set_derivative\)\(__mknobXt\d*?__,Sparso.DERIVATIVE_TYPE_TRANSPOSE,__mknobX\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Xw,X,x,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.element_wise_multiply!\)\(yXw,y,Xw\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.abs!\)\(__temp.*?,yXw\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(__temp.*?,-1,__temp.*?,0,__temp.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.exp!\)\(__temp.*?,__temp.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.log1p!\)\(__temp.*?,__temp.*?\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.sum\)\(\(Sparso.WAXPBY!\)\(__temp.*?,1,__temp.*?,-1,\(Sparso.min!\)\(__temp.*?,yXw,0\)\)\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?fk0 = s / m \+ \(lambda / 2\) \* \(Sparso.dot\)\(x,x\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.exp!\)\(__temp.*?,yXw\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.element_wise_divide!\)\(temp,y,\(Sparso.WAXPB!\)\(__temp.*?,1,__temp.*?,1\)\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(dfk,-1 / m,Xt,temp,lambda,x,0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.reordering\)\(__fknob\d*?__,__reordering_status\d*?__,X,Sparso.COL_INV_PERM,Sparso.ROW_INV_PERM,__mknobX\d*?__,:__delimitor__,y,Sparso.COL_INV_PERM,dx,Sparso.ROW_PERM\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?unless \(Sparso.norm\)\(dfk\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.reverse_reordering\)\(__reordering_status\d*?__,:__delimitor__,x,Sparso.ROW_PERM\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(w,1,x,-alpha,dfk\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Xw,1,X,w,0.0,Xw,0.0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.element_wise_multiply!\)\(yXw,y,Xw\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?fk = s / m \+ \(lambda / 2\) \* \(Sparso.dot\)\(w,w\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.dot\)\(dfk,dfk\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(x,1,x,alpha,dx\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Xw,1,X,x,0.0,Xw,0.0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(dfkp1,-1 / m,Xt,temp,lambda,x,0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(__temp.*?,1,dfkp1,-1,dfk\)",
                     "Test accelerated"
        ),
        exception_pattern
    ]
)

const lbfgs_test2 = Test(
    "lbfgs-test2",
    "lbfgs-new.jl $MTX_covtype",
    [
        TestPattern(r"Original L-BFGS:      32 iterations f = 0.00000000004134",
                     "Test original"
        ),
        TestPattern(r"Opt L-BFGS:      32 iterations f = 0.00000000004134",
                     "Test optimized version"
        ),
        TestPattern(r"Opt_with_reordering L-BFGS:      33 iterations f = 0.0000000000",
                     "Test Opt_with_reordering"
        ),
        TestPattern(r"Accelerated L-BFGS:      3[345] iterations f = 0.00000000",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobXt.*? = \(Sparso.new_matrix_knob\)\(:Xt,true,true,false,false,false,false\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?mknobX.*? = \(Sparso.new_matrix_knob\)\(:X,true,true,false,false,false,false\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.set_derivative\)\(__mknobXt\d*?__,Sparso.DERIVATIVE_TYPE_TRANSPOSE,__mknobX\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Xw,1,X,x,0.0,Xw,0.0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.element_wise_multiply!\)\(yXw,y,Xw\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(dfk,-1 / m,Xt,temp,lambda,x,0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.reordering\)\(__fknob\d*?__,__reordering_status\d*?__,X,Sparso.COL_INV_PERM,Sparso.ROW_INV_PERM,__mknobX\d*?__,:__delimitor__,y,Sparso.COL_INV_PERM,dx,Sparso.ROW_PERM\)
",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?unless \(Sparso.norm\)\(dfk\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.reverse_reordering\)\(__reordering_status\d*?__,:__delimitor__,x,Sparso.ROW_PERM\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(w,1,x,-alpha,dfk\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(Xw,1,X,w,0.0,Xw,0.0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.element_wise_multiply!\)\(yXw,y,Xw\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?Sparso.dot\)\(dfk,dfk\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(dfkp1,-1 / m,Xt,temp,lambda,x,0,__fknob\d*?__\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.reverse_reordering\)\(__reordering_status\d*?__,:__delimitor__,x,Sparso.ROW_PERM\)",
                     "Test accelerated"
        ),
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(__temp.*?,1,dfkp1,-1,dfk\)",
                     "Test accelerated"
        ),
        exception_pattern
    ]
)
end

const MTX_small_diag = "../matrices/small-diag.mtx"

const liveness_test1 = Test(
    "liveness-test1",
    "liveness-test1.jl $MTX_small_diag",
    [
        TestPattern(r"Def",
                     "Test liveness for cg."
        ),
        exception_pattern
    ]
)

const liveness_test2 = Test(
    "liveness-test2",
    "liveness-test2.jl",
    [
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.*bigM.* A .*\) Use\(",
                        "Test liveness for ipm-ref: A should not be updated in the block that sets bigM"
        ),
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.* A .*bigM.*\) Use\(",
                        "Test liveness for ipm-ref: A should not be updated in the block that sets bigM"
        ),
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.*Rd.* A .*\) Use\(",
                        "Test liveness for ipm-ref: A should not be updated in the block that sets Rd"
        ),
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.* A .*Rd.*\) Use\(",
                        "Test liveness for ipm-ref: A should not be updated in the block that sets Rd"
        ),
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.* mu .*\) Use\(.*\n.* = mu <=",
                        "Test liveness for ipm-ref: mu should not be updated in the block that tests mu <= 1.0e-7"
        ),
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.*blas1_time.* relResidual .*\) Use\(.*\n\s*blas1_time =.*\n.*Ac_mul_B",
                        "Test liveness for ipm-ref: relResidual, x, p should not be updated in the block that sets blas1_time"
        ),
        AntiTestPattern(r"Liveness of basic blocks:(.|\n)*?Def\(.* relResidual .*blas1_time.*\) Use\(.*\n\s*blas1_time =.*\n.*Ac_mul_B",
                        "Test liveness for ipm-ref: relResidual, x, p should not be updated in the block that sets blas1_time"
        ),
        exception_pattern
    ]
)

const call_replacement_test1 = Test(
    "call-replacement-test1",
    "call-replacement-test1.jl $MTX_small_diag",
    [
        TestPattern(r"AST:(.|\n)*?Main.dot(.|\n)*?New AST(.|\n)*?Sparso.dot",
                     "Test call replacement of Main.dot with Sparso.dot."
        ),
        exception_pattern
    ]
)

const call_replacement_test2 = Test(
    "call-replacement-test2",
    "call-replacement-test2.jl $MTX_small_diag",
    [
        TestPattern(r"AST:(.|\n)*?\(Sparso.SpMV\)\(A,x\)",
                     "Test call replacement of * with Sparso.SpMV."
        ),
        exception_pattern
    ]
)

const call_replacement_test3 = Test(
    "call-replacement-test3",
    "call-replacement-test3.jl $MTX_small_diag",
    [
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(y,A,x\)",
                     "Test call replacement of SpMV! for A_mul_B!(y, A, x)."
        ),
        exception_pattern
    ]
)

const call_replacement_test4 = Test(
    "call-replacement-test4",
    "call-replacement-test4.jl $MTX_small_diag",
    [
        TestPattern(r"New AST:(.|\n)*?\(Sparso.SpMV!\)\(y,0.1,A,x,0.1,y,0.0\)",
                     "Test call replacement of SpMV for A_mul_B!(0.1, A, x, 0.1, y)."
        ),
        exception_pattern
    ]
)

const call_replacement_test5 = Test(
    "call-replacement-test5",
    "call-replacement-test5.jl $MTX_small_diag",
    [
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(x,1,x,alpha,p\)",
                     "Test call replacement of WAXPBY! for x += alpha * p."
        ),
        exception_pattern
    ]
)

const call_replacement_test6 = Test(
    "call-replacement-test6",
    "call-replacement-test6.jl $MTX_small_diag",
    [
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(x,1,x,-alpha,p\)",
                     "Test call replacement of WAXPBY! for x -= alpha * p."
        ),
        exception_pattern
    ]
)

const call_replacement_test7 = Test(
    "call-replacement-test7",
    "call-replacement-test7.jl $MTX_small_diag",
    [
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(p,1,r,beta,p\)",
                     "Test call replacement of WAXPBY! for p = r + beta * p."
        ),
        exception_pattern
    ]
)

const call_replacement_test8 = Test(
    "call-replacement-test8",
    "call-replacement-test8.jl $MTX_small_diag",
    [
	TestPattern(r"New AST:(.|\n)*?Sparso.SpMV\)\(1 - r,A,p\),r\)",
                     "Test call replacement of SpMV! in simple page rank."
        ),
        exception_pattern
    ]
)

const call_replacement_test9 = Test(
    "call-replacement-test9",
    "call-replacement-test9.jl $MTX_small_diag",
    [
        TestPattern(r"sum of x=-1.57731204341073\d*e-5",
                     "Test orig sum"
        ),

        TestPattern(r"accel sum of x=-1.57731204341073\d*e-5",
                     "Test accelerated sum"
        ),

        exception_pattern
    ]
)

const call_replacement_test10 = Test(
    "call-replacement-test10",
    "call-replacement-test10.jl $MTX_small_diag",
    [
        TestPattern(r"sum of x=-1.5773120434107\d*e-5",
                     "Test orig sum"
        ),

        TestPattern(r"accel sum of x=-1.5773120434107\d*e-5",
                     "Test accelerated sum"
        ),
        exception_pattern
    ]
)

const call_replacement_test11 = Test(
    "call-replacement-test11",
    "call-replacement-test11.jl $MTX_small_diag",
    [
        TestPattern(r"sum of x=-1.5773120434107\d*e-5",
                     "Test orig sum"
        ),

        TestPattern(r"accel sum of x=-1.5773120434107\d*e-5",
                     "Test accelerated sum"
        ),
        exception_pattern
    ]
)

const call_replacement_test12 = Test(
    "call-replacement-test12",
    string("call-replacement-test12.jl  ", CG_MATRIX),
    [
        TestPattern(r"New AST:(.|\n)*?\(Sparso.WAXPBY!\)\(p,1,z,beta,p\)",
                     "Test call replacement of WAXPBY! for p = r + beta * p."
        ),
        exception_pattern
    ]
)

const name_resolution_test1 = Test(
    "name-resolution-test1",
    "name-resolution-test1.jl $MTX_small_diag",
    [
        TestPattern(r"Module name: X\.Y\.Z\.U\.V\.W\nFunction name: f(.|\n)*?Module name: Main\nFunction name: \*",
                     "Test name resolution."
        ),
        exception_pattern
    ]
)

#
function gen_set_regex_string(
    set :: Array
)
    ret = "\\["
    for e in set
        ret = ret * "[^:]*:" * string(e)
    end
    ret = ret * "[^:]*\\]"
    ret
end

const constant_value_test1 = Test(
    "constant-value-test1",
    "constant-value-test1.jl ipm/mps/osa-14",
    [
        TestPattern(r"Constants discovered:.*\n.*\[(:A,?|:b,?|:p,?){3,3}\]",
                     "Test ipm-ref that A, b and p are recognized as loop constants."
        ),
        exception_pattern
    ]
)

const single_def_test1 = Test(
    "single-def-test1",
    "single-def-test1.jl",
    [
        TestPattern(Regex("Single-defs discovered:.*\\n.*\[.*[^:]*:B[^:].*\]"),
                     "Test ipm-ref that B is recognized as single-defs in the loop."
        ),
        TestPattern(Regex("Single-defs discovered:.*\\n.*\[.*[^:]*:D[^:].*\]"),
                     "Test ipm-ref that D is recognized as single-defs in the loop."
        ),
        TestPattern(Regex("Single-defs discovered:.*\\n.*\[.*[^:]*:R[^:].*\]"),
                     "Test ipm-ref that R is recognized as single-defs in the loop."
        ),
        exception_pattern
    ]
)

const single_def_test2 = Test(
    "single-def-test2",
    "single-def-test2.jl",
    [
        TestPattern(Regex("Single-defs discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test ipm-ref that A B are recognized as single-defs in the loop."
        ),
        exception_pattern
    ]
)

const set_matrix_property_test1 = Test(
    "set-matrix-property-test1",
    "set-matrix-property-test1.jl",
    [
        TestPattern(Regex("Loop0 Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that A B are recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that A is recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Structure symmetry discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that R is recognized as constant in structure."
        ),
        exception_pattern
    ]
)

const set_matrix_property_test2 = Test(
    "set-matrix-property-test2",
    "set-matrix-property-test2.jl",
    [

        TestPattern(Regex("Loop0 Matrix structures discovered:.*\\n.*" * gen_set_regex_string([:A, :L, :U])),
                     "Test that A L U are recognized as matrics in structure."
        ),

        TestPattern(Regex("Loop0 Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A, :L, :U])),
                     "Test that A L U are recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Structure symmetry discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that R is recognized as constant in structure."
        ),
        exception_pattern
    ]
)

const set_matrix_property_test3 = Test(
    "set-matrix-property-test3",
    "set-matrix-property-test3.jl",
    [
        TestPattern(Regex("Func Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that A B are recognized as constant in structure."
        ),

        TestPattern(Regex("Func Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as constant in structure."
        ),

        TestPattern(Regex("Func Structure symmetry discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that R is recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that A B are recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as constant in structure."
        ),

        TestPattern(Regex("Loop0 Structure symmetry discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that R is recognized as constant in structure."
        ),
        exception_pattern
    ]
)

const set_matrix_property_test4 = Test(
    "set-matrix-property-test4",
    "set-matrix-property-test4.jl",
    [

        TestPattern(Regex("Func Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as matrics in structure."
        ),

        TestPattern(Regex("Loop0 Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as matrics in structure."
        ),

        TestPattern(Regex("Loop3 Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that A B are recognized as constant in structure."
        ),

        exception_pattern
    ]
)

const set_matrix_property_test5 = Test(
    "set-matrix-property-test5",
    "set-matrix-property-test5.jl",
    [
        TestPattern(r"Func Upper/Lower matrix discovered:.*\n[\s]*A is lower of B",
                     "Test that A is recognized as lower part of B."
        ),
        TestPattern(r"Loop0 Upper/Lower matrix discovered:.*\n[\s]*A is lower of B",
                     "Test that A is recognized as lower part of B."
        ),
        TestPattern(r"Loop3 Upper/Lower matrix discovered:.*\n[\s]*A is lower of B.*\n[\s]*B is upper of C",
                     "Test that A is recognized as matrics in structure."
        ),
        exception_pattern
    ]
)

const set_matrix_property_test6 = Test(
    "set-matrix-property-test6",
    "set-matrix-property-test6.jl",
    [

        TestPattern(Regex("Func Structure only discovered:.*\\n.*" * gen_set_regex_string([:A, :C])),
                     "Test that A is recognized as structure-only matrix."
        ),

        TestPattern(Regex("Loop0 Structure only discovered:.*\\n.*" * gen_set_regex_string([:A, :C])),
                     "Test that A C are recognized as structure-only matrics."
        ),

        exception_pattern
    ]
)

const set_matrix_property_test7 = Test(
    "set-matrix-property-test7",
    "set-matrix-property-test7.jl",
    [
        TestPattern(r"Func Transpose matrix discovered:.*\n[\s]*A is transpose of B",
                     "Test that A is recognized as transpose of B."
        ),
        TestPattern(r"Loop0 Transpose matrix discovered:.*\n[\s]*A is transpose of B\n[\s]*B is transpose of C",
                     "Test that A is recognized as transpsoe of C."
        ),

        exception_pattern
    ]
)

const prop_constant_structure_test1 = Test(
    "prop-constant-structure-test1",
    "prop-constant-structure-test1.jl ipm/mps/osa-14",
    [
        TestPattern(Regex("Loop-4 Constant structures discovered:.*\\n.*" * gen_set_regex_string([:A, :B, :D, :R])),
                     "Test that A B D R are recognized as constant in structure."
        ),
        exception_pattern
    ]
)

const prop_symmetric_value_test1 = Test(
    "prop-symmetric-value-test1",
    "prop-symmetric-value-test1.jl",
    [
        TestPattern(Regex("Loop0 Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:B, :E, :F, :G, :S])),
                     "Test that B E F S is recognized as symmetric in value."
        ),
        exception_pattern
    ]
)

const prop_symmetric_value_test2 = Test(
    "prop-symmetric-value-test2",
    "prop-symmetric-value-test2.jl",
    [
        TestPattern(r"Value symmetry discovered:.*\n.*\[.*:A.*\]",
                     "Test that A is recognized as symmetric in value."
        ),
        exception_pattern
    ]
)

const prop_symmetric_value_test3 = Test(
    "prop-symmetric-value-test3",
    "prop-symmetric-value-test3.jl",
    [
        TestPattern(Regex("Loop0 Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:B, :C, :G, :S])),
                     "Test that B E F G S are recognized as symmetric in value."
        ),
        exception_pattern
    ]
)

const prop_symmetric_value_test4 = Test(
    "prop-symmetric-value-test4",
    "prop-symmetric-value-test4.jl",
    [
        TestPattern(Regex("Loop0 Value symmetry discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that B E F G S are recognized as symmetric in value."
        ),
        exception_pattern
    ]
)

const prop_symmetric_structure_test1 = Test(
    "prop-symmetric-structure-test1",
    "prop-symmetric-structure-test1.jl",
    [
        TestPattern(Regex("Structure symmetry discovered:.*\\n.*" * gen_set_regex_string([:A, :B])),
                     "Test that A B are recognized as symmetric in structure."
        ),
        exception_pattern
    ]
)

const prop_structure_only_test1 = Test(
    "prop-structure-only-test1",
    "prop-structure-only-test1.jl",
    [
        TestPattern(Regex("Func Structure only discovered:.*\\n.*" * gen_set_regex_string([:B, :C, :E])),
                     "Test that B C E are recognized as pattern-only structure."
        ),
        exception_pattern
    ]
)

const prop_structure_only_test2 = Test(
    "prop-structure-only-test2",
    "prop-structure-only-test2.jl",
    [
        TestPattern(Regex("Func Structure only discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as pattern-only structure."
        ),
        exception_pattern
    ]
)

const prop_structure_only_test3 = Test(
    "prop-structure-only-test3",
    "prop-structure-only-test3.jl",
    [
        TestPattern(Regex("Func Structure only discovered:.*\\n.*" * gen_set_regex_string([:A])),
                     "Test that A is recognized as pattern-only structure."
        ),
        exception_pattern
    ]
)

const prop_lower_upper_test1 = Test(
    "prop-lower-upper-test1",
    "prop-lower-upper-test1.jl",
    [
        TestPattern(r"Func Upper/Lower matrix discovered:.*\n[\s]*D is upper of A.*\n[\s]*GenSym\(0\) is upper of A",
                     "Test D and GenSym(0) are upper part of A."
        ),
        exception_pattern
    ]
)

const prop_lower_upper_test2 = Test(
    "prop-lower-upper-test2",
    "prop-lower-upper-test2.jl",
    [
        TestPattern(r"Loop0 Upper/Lower matrix discovered:.*\n[\s]*C is lower of A.*\n[\s]*D is upper of A.*\n[\s]*E is lower of A.*\n[\s]*F is upper of A.*\n[\s]*L is lower of A",
                     "Test that A B are recognized as symmetric in structure."
        ),
        exception_pattern
    ]
)

const prop_transpose_test1 = Test(
    "prop-transpose-test1",
    "prop-transpose-test1.jl",
    [
        TestPattern(r"Func Transpose matrix discovered:.*\n[\s]*At is transpose of A.*\n[\s]*Att is transpose of At.*\n[\s]*B is transpose of A.*",
                     "Test D and GenSym(0) are upper part of A."
        ),
        exception_pattern
    ]
)

const all_tests = [
    sanity_test1,
    sanity_test2,
    sanity_test3,
    spmv_sanity_test1,
    context_test1,
    context_test2,
    context_test2_without_reordering,
    context_test2_ilu0,
    context_test3,
    context_test4,
    context_test5,
    pagerank_test1,
    cosp2_test1,
#    lbfgs_test1,
#    lbfgs_test2,
    liveness_test1,
    liveness_test2,
    call_replacement_test1,
    call_replacement_test2,
    call_replacement_test3,
    call_replacement_test4,
    call_replacement_test5,
    call_replacement_test6,
    call_replacement_test7,
    call_replacement_test8,
    call_replacement_test9,
    call_replacement_test10,
    call_replacement_test11,
    call_replacement_test12,
    name_resolution_test1,
    single_def_test1,
#    single_def_test2,
    constant_value_test1,
    set_matrix_property_test1,
#    set_matrix_property_test2,
    set_matrix_property_test3,
#    set_matrix_property_test4,
    set_matrix_property_test5,
    set_matrix_property_test6,
    set_matrix_property_test7,
    prop_constant_structure_test1,
#    prop_symmetric_value_test1,
#    prop_symmetric_value_test2,
#    prop_symmetric_value_test3,
#    prop_symmetric_value_test4,
#    symmetric_structure_test1,
#    prop_structure_only_test1,
#    prop_structure_only_test2,
#    prop_structure_only_test3,
    prop_lower_upper_test1,
    prop_lower_upper_test2,
    prop_transpose_test1,
]

const fast_tests = [
#    context_test1,
    context_test2,
    context_test2_without_reordering,
    context_test3,
    context_test4,
    context_test5,
    pagerank_test1,
    cosp2_test1,
#    lbfgs_test1,
]

# If true, use pcregrep for regular expression match.
# If false, use Julia (If PCRE JIT stack overflow: enlarge JIT_STACK_MAX_SIZE in
# julia/base/pcre.jl (times it with 10) and retry).
const USE_PCREGREP_REGEX_MATCH = true

function get_julia_ver()
    s, p = open(`$julia_command -v`)
    readline(s)
end

if !isreadable(julia_command)
    error("Please install (softlink) julia command to \"" * julia_command  * "\".")
elseif !ismatch(r"\.*0.4.1", get_julia_ver())
#    error("Wrong julia version! 0.4.1 is required!")
end

if isreadable("regression.conf")
    include("regression.conf")
    tests = local_tests
else
    tests = fast_tests
end

if length(ARGS) > 0
    if ARGS[1] == "all"
        tests = all_tests
    elseif ARGS[1] == "fast"
        tests = fast_tests
    elseif ARGS[1] == "none"
        tests = []
    else
        matched_tests = []
        for t in all_tests
            if startswith(t.name, ARGS[1])
                push!(matched_tests, t)
            end
        end
        if !isempty(matched_tests)
            tests = matched_tests
        else
            print("No testing group matched.\n")
        end
    end
    print(length(tests), " test(s).\n")
end

ENV["JULIA_LOAD_PATH"] = root_path * "/deps"
# avoid package precompilation issue
run(`$julia_command precompl.jl`)

@doc """
Run a test
"""
function run_test(
    test :: Test
)
    log  = string(test.name, ".log")

    # Run the command. Redirect output to the log file
    split_res = split(test.command)
    cmd = `$julia_command $split_res`
    successful = success(pipeline(cmd, stdout=log, stderr=log, append=false))

    # Some patterns are not intended to run, but to check compiler outputs
    # expected code
    # TODO: maybe we should add a field to a test to indicate if it should be
    # executed?
    successful = true

    if successful
        # Match with patterns
        log_file = open(log, "a")
        for pattern in test.patterns
            assert(typeof(pattern) == TestPattern || typeof(pattern) == AntiTestPattern)
            if !USE_PCREGREP_REGEX_MATCH
                # Read the output to a string
                output = open(readall, log)
                m       = match(pattern.pattern, output)
                matched = (m != nothing)
            else
                pattern_str = pattern.pattern.pattern

                cmd  = `pcregrep --buffer-size=10000000 -M $pattern_str $log`
                matched = success(pipeline(cmd, stdout=DevNull, stderr=DevNull))
            end
            if (!matched && typeof(pattern) == TestPattern) ||
               ( matched && typeof(pattern) == AntiTestPattern)
                comment = pattern.comment
                write(log_file, "\n****** Failed in ",
                    (typeof(pattern) == AntiTestPattern) ? "anti-pattern\n\t" : "pattern\n\t",
                    string(pattern.pattern), "\n\tComment: ", comment)
                successful = false
            end
        end
        close(log_file)
    end

    if successful
        #rm(log)
    end

    successful
end

total = length(tests)
succ = 0
passed = Dict()
if nprocs() == 1 # single thread mode
    for test in tests
        print("Testing ", test.name)
        s = run_test(test)
        if s
            succ = succ + 1
            println(": Pass")
	    passed[test.name] = true
        else
            println(": FAIL. See ", test.name * ".log")
	    passed[test.name] = false
        end
    end
else
    tasks = []
    task_map = Dict()
    for test in tests
        push!(tasks, @schedule(run_test(test)))
        task_map[last(tasks)] = test
        sleep(0.5)
    end
    finished = []
    running  = []
    while length(finished) < total
        for t in tasks
            if istaskdone(t)
                if !in(t, finished)
                    push!(finished, t)
                    name = task_map[t].name
                    ret = wait(t)
                    print(length(finished), "/", total, " ")
                    if ret
                        println(name, ": Pass")
                        passed[name] = true
                    else
                        println(name, ": FAIL. See ", name * ".log")
                        passed[name] = false
                    end
                    succ = succ + ret
                end
            elseif istaskstarted(t)
                if !in(t, running)
                    push!(running, t)
                    name = task_map[t].name
                    println("Testing ", name)
                end
            end
        end
        sleep(0.5)
    end

end

# Print out the results in a fixed order for easier checking
println("\nFinal report:")
for test in tests
    println(test.name, ": ", passed[test.name] ? "Pass" : "FAIL. See $(test.name).log")
end

println("Total: ", total)
println("Pass : ", succ)
println("Fail : ", total-succ)

max_stars_repo_name: IntelLabs/Sparso

max_issues_repo_name: IntelLabs/Sparso

max_forks_repo_name: IntelLabs/Sparso


text:
# FileDataset

function FileDataset(dir, pattern="*")
    return rglob(pattern, string(dir))
end

pathparent(p::String) = splitdir(p)[1]
pathname(p::String) = splitdir(p)[2]

# File utilities

"""
    rglob(filepattern, dir = pwd(), depth = 4)

Recursive glob up to 6 layers deep.
"""
function rglob(filepattern = "*", dir = pwd(), depth = 4)
    patterns = [
        "$filepattern",
        "*/$filepattern",
        "*/*/$filepattern",
        "*/*/*/$filepattern",
        "*/*/*/*/$filepattern",
        "*/*/*/*/*/$filepattern",
    ]
    return vcat([glob(pattern, dir) for pattern in patterns[1:depth]]...)
end

"""
    loadfile(file)

Load a file from disk into the appropriate format.
"""
function loadfile(file::String)
    if isimagefile(file)
        # faster image loading
        return FileIO.load(file, view = true)
    elseif endswith(file, ".csv")
        return DataFrame(CSV.File(file))
    else
        return FileIO.load(file)
    end
end

loadfile(file::AbstractPath) = loadfile(string(file))

#TableDataset

struct TableDataset{T}
    table::T #Should implement Tables.jl interface
    TableDataset{T}(table::T) where T = Tables.istable(table) ? new{T}(table) : error("Object doesn't implement Tables.jl interface")
end

TableDataset(table::T) where {T} = TableDataset{T}(table)
TableDataset(path::AbstractPath) = TableDataset(DataFrame(CSV.File(path)))

function LearnBase.getobs(dataset::FastAI.Datasets.TableDataset, idx)
    if Tables.rowaccess(dataset.table)
        row, _ = Iterators.peel(Iterators.drop(Tables.rows(dataset.table), idx - 1))
        return row
    elseif Tables.columnaccess(dataset.table)
        colnames = Tables.columnnames(dataset.table)
        rowvals = [Tables.getcolumn(dataset.table, i)[idx] for i in 1:length(colnames)]
        return (; zip(colnames, rowvals)...)
    else
        error("The Tables.jl implementation used should have either rowaccess or columnaccess.")
    end
end

function LearnBase.nobs(dataset::TableDataset)
    if Tables.columnaccess(dataset.table)
        return length(Tables.getcolumn(dataset.table, 1))
    elseif Tables.rowaccess(dataset.table)
        return length(Tables.rows(dataset.table)) # length might not be defined, but has to be for this to work.
    else
        error("The Tables.jl implementation used should have either rowaccess or columnaccess.")
    end
end

LearnBase.getobs(dataset::TableDataset{<:DataFrame}, idx) = dataset.table[idx, :]
LearnBase.nobs(dataset::TableDataset{<:DataFrame}) = nrow(dataset.table)

LearnBase.getobs(dataset::TableDataset{<:CSV.File}, idx) = dataset.table[idx]
LearnBase.nobs(dataset::TableDataset{<:CSV.File}) = length(dataset.table)

ext: jl


text:
include("acrobot.jl")
include("cartpole.jl")
include("mountaincar.jl")
include("pinball/pinball.jl")
include("bicycle.jl")
include("hiv.jl")
include("pendulum.jl")
include("ballandbeam.jl")


text:
# ---
# jupyter:
#   jupytext:
#     formats: ipynb,jl:hydrogen
#     text_representation:
#       extension: .jl
#       format_name: hydrogen
#       format_version: '1.3'
#       jupytext_version: 1.11.2
#   kernelspec:
#     display_name: Julia 1.6.2
#     language: julia
#     name: julia-1.6
# ---

# %% [markdown]
# * https://discourse.julialang.org/t/for-monte-carlo-simulation-with-same-code-same-algorithm-how-fast-is-julia-compared-with-fortran/67021/41
# * https://discourse.julialang.org/t/for-monte-carlo-simulation-with-same-code-same-algorithm-how-fast-is-julia-compared-with-fortran/67021/43
# * https://github.com/genkuroki/public/blob/main/0018/%40defkwargs.ipynb
# * https://github.com/genkuroki/public/blob/main/0018/%40defunpack.ipynb
# * https://github.com/genkuroki/public/blob/main/0018/How%20to%20define%20unpacking%20macros.ipynb
# * https://github.com/genkuroki/public/blob/main/0018/How%20to%20define%20unpacking%20macros%20Part%202.ipynb

# %%
struct Foo{A, B, C} a::A; b::B; c::C end

"""
`@unpackall_Foo(obj)` unpacks all fields of the object `obj` of type `Foo`.
"""
macro unpackall_Foo(obj)
    names = fieldnames(Foo)
    Expr(:(=),
        Expr(:tuple, names...),
        Expr(:tuple, (:($obj.$name) for name in names)...)
    ) |> esc
end

@doc @unpackall_Foo

# %%
@macroexpand @unpackall_Foo foo

# %%
@unpackall_Foo Foo(1, 2.0, "three")

# %%
a, b, c

# %%
foo = Foo(1, 2.0, "three")

function f(foo::Foo)
    @unpackall_Foo foo
    @show a b c
    return
end

f(foo)

# %%

max_stars_repo_path: 0018/How to define unpacking macros.jl

max_stars_repo_name: genkuroki/public

max_issues_repo_path: 0018/How to define unpacking macros.jl

max_issues_repo_name: genkuroki/public

max_forks_repo_path: 0018/How to define unpacking macros.jl

max_forks_repo_name: genkuroki/public


text:
"""
$(TYPEDEF)

Abstract type for a (possibly infinite) immutable set of surreal numbers.
"""
abstract type SurrealSet{T} end

SurrealSet(s::SurrealSet) = s
SurrealSet(x::Number) = Singleton(x)
SurrealSet(s) = hasmethod(iterate, Tuple{typeof(s)}) ? WrappedSurrealSet(s) : Singleton(x)
SurrealSet() = EmptySurrealSet()

Base.eltype(::SurrealSet{T}) where T = T

"""
$(TYPEDSIGNATURES)

Whether the set has an infinite number of elements.

Based off of `Base.IteratorSize`, subclasses of `SurrealSet` should add methods
to that function rather than this one.
"""
issetfinite(s::SurrealSet) = Base.IteratorSize(s) != Base.IsInfinite()

#
# Ordering
#

"""
	$(FUNCTIONNAME)(A::SurrealSet, B::SurrealSet)
	$(FUNCTIONNAME)(a::Number, B::SurrealSet)
	$(FUNCTIONNAME)(A::SurrealSet, b::Number)

If all elements of A are < all elements of B.

If either argument is a scalar it is treated as a singleton.
"""
function all_lt end

"""
	$(FUNCTIONNAME)(A::SurrealSet, B::SurrealSet)
	$(FUNCTIONNAME)(a::Number, B::SurrealSet)
	$(FUNCTIONNAME)(A::SurrealSet, b::Number)

If all elements of A are ≤ all elements of B.

If either argument is a scalar it is treated as a singleton.
"""
function all_lte end

for (f, op) in [(:all_lt, <), (:all_lte, <=)]
	@eval begin
		function $f(a::SurrealSet, b::SurrealSet)
			issetfinite(a) && return $f(maximum(a), b)
			issetfinite(b) && return $f(a, minimum(b))
			throw(NotImplementedError($f, (a, b)), "Not implemented for two infinite sets")
		end

		function $f(a::SurrealSet, b::Number)
			issetfinite(a) && return $op(maximum(a), b)
			throw(NotImplementedError($f, (a, b)), "Not implemented for infinite sets")
		end

		function $f(a::Number, b::SurrealSet)
			issetfinite(b) && return $op(a, minimum(b))
			throw(NotImplementedError($f, (a, b)), "Not implemented for infinite sets")
		end
	end
end


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder

"""
    offset_version(upstream, offset)

Compute a version that allows distinguishing between changes in the upstream
version and changes to the JLL which retain the same upstream version.

When the `upstream` version is changed, `offset` version numbers should be reset
to `v"0.0.0"` and incremented following semantic versioning.
"""
function offset_version(upstream, offset)
    return VersionNumber(
        upstream.major * 100 + offset.major,
        upstream.minor * 100 + offset.minor,
        upstream.patch * 100 + offset.patch,
    )
end

function gap_pkg_name(name::String)
    # turn the name into a canonical form; in particular, since GAP
    # treats package names case insensitive, but Julia does not, turn
    # them all into lowercase to protect against accidental changes.
    # This allows us elsewhere to generate Julia  and GAP code
    # referencing these JLLs in a uniform way.
    return "GAP_pkg_$(lowercase(name))"
end

function setup_gap_package(gap_version::VersionNumber; uses_cxx::Bool = false)

    platforms = supported_platforms()
    filter!(p -> nbits(p) == 64, platforms) # we only care about 64bit builds
    filter!(!Sys.iswindows, platforms)      # Windows is not supported

    if uses_cxx
        platforms = expand_cxxstring_abis(platforms)
    end

    # the added 5 corresponds to "Julia 1.5". Doesn't really matter, except if
    # we don't add this, then BB tries to install the JLL "for Julia 1.0" which doesn't exist.
    mod_gap_version = VersionNumber(gap_version.major, gap_version.minor, gap_version.patch + 5)
    dependencies = BinaryBuilder.AbstractDependency[
        Dependency("GAP_jll", mod_gap_version; compat="~$(gap_version)"),
        Dependency("GAP_lib_jll", gap_version; compat="~$(gap_version)"),
    ]

    # HACK HACK HACK: the gac and sysinfo.gap shipped in GAP_jll are currently broken.
    # We modify sources and script below to work around that. This should eventually go,
    # once GAP_jll is fixed

    global sources
    sources = [
        DirectorySource("../bundled"),
        sources...
    ]

    global script
    script = raw"""
    # HACK WORKAROUND GAP_jll deficiencies
    # TODO: tweak for mac build
    if [[ "${target}" == *darwin* ]]; then
      cp gac-darwin ${prefix}/share/gap/gac
    else
      cp gac ${prefix}/share/gap/gac
    fi
    chmod a+x ${prefix}/share/gap/gac
    cp sysinfo.gap ${prefix}/share/gap/

    # ensure #including src/compiled.h or src/profile.h from GAP_jll works
    ln -s . /workspace/destdir/include/gap/src
    """ * script

    return platforms, dependencies
end

max_stars_repo_name: singularitti/Yggdrasil

max_issues_repo_name: singularitti/Yggdrasil

max_forks_repo_name: singularitti/Yggdrasil


text:
# Copyright (c) 2022 Code Komali
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT

using Test

# Generate prime using the sieve of eratosthenes approach
function generateprime(limit)
    limit > 0 || throw(ArgumentError("limit must be > 0"))
    boolArray = fill!(Vector{Bool}(undef,limit), true) #may be simplified
    boolArray[1] = false
    for num in 2:limit
        if boolArray[num] == false
            continue
        end
        # Don't touch the element, just its multiples. Hence starting from num*2.
        for j in (num*2):num:limit
            boolArray[j] = false
        end
    end
    return primeindexes(boolArray)
end

#TODO: need to test which one of the below works faster
function primeindexes(boolArray)
    filter(x -> x!=-1, #filter all -1
            #note: the additional comma is required for destructing tuples in anonymous functions
            map(((i,v),)->v ? i : -1, #if value is true return index otherwise -1
                enumerate(boolArray))) # enumerate index and value as list of tuples
end

function primeindexes_alt(boolArray)
    #note: the additional comma is required for destructing tuples in anonymous functions
    map(((i,_),)->i, # return only the index from the tuples
        filter(
            ((_,v),) -> v, # filter all tuples with 'false' val
            collect(enumerate(boolArray)))) #enumerate to get (index, val) tuples and collect them in a vector
end

@testset "sieve of erastosthenes" begin
    @test generateprime(20) == [2, 3, 5, 7, 11, 13, 17, 19]
    @test generateprime(1) == []
    @test_throws ArgumentError generateprime(0)
end

max_stars_repo_name: codekomali/JuliaPractice

max_issues_repo_name: codekomali/JuliaPractice

max_forks_repo_name: codekomali/JuliaPractice


text:
abstract type priorType end

"""
Represents a uniform prior on range = [a, b]
"""
struct Uniform <:priorType
    range::Array{Real, 2} #admissible ranges for each length scale ([lowerbound_i, upperbound_i]), stacked vertically
    d::Int64 #number of ranges in range object/number length scales
    lengths::Array{Real, 1}
    function Uniform(range) #inner constructor allows one to enforce constraints
        @assert typeof(range)<:Union{Array{T, 2}, Array{T, 1}} where T<:Real
        if length(range) > 1
            @assert prod(range[:, 2]- range[:, 1] .> 0) #ranges must be valid
            lengths = range[:, 2] - range[:, 1]
            if typeof(range)<:Array{Real, 1}
                range = reshape(range, 1, 2)
                return new(range, 1, lengths)
            else
                @assert Base.size(range, 2) == 2
                return new(range, Base.size(range, 1), lengths)
            end
        else
            return new(range, Base.size(range, 1), ones(size(range, 1)))
        end
    end
end

getRange(u::Uniform) = u.range #internal range array
getNum(u::Uniform) = u.d #number of dimensions of interal range array
getLengths(u::Uniform) = u.lengths
logProb(u::Uniform, x) = (@assert length(x) == u.d; l = getLengths(u); -sum(log.(l)))#density function
prob(u::Uniform, x) = (@assert length(x) == u.d; l = getLengths(u); 1/prod(l))#density function
partialx(u::Uniform, x) = 0

"""
Represents a prior on [1/b, 1/a] that induces a uniform distribution on range = [a, b]
"""
struct inverseUniform<:priorType
    range::Array
    d::Int64 #number of ranges in range object/number length scales
    lengths::Array{Real, 1}
    function inverseUniform(range)
        if length(range) > 1
            @assert prod(range[:, 2]- range[:, 1] .> 0) #ranges must be valid
            lengths = range[:, 2] - range[:, 1]
            if typeof(range)<:Array{Real, 1}
                range = reshape(range, 1, 2)
                return new(range, 1, lengths)
            else
                @assert Base.size(range, 2) == 2
                return new(range, Base.size(range, 1), lengths)
            end
        else
            return new(range, Base.size(range, 1), ones(size(range, 1)))
        end
    end
end
getLengths(u::inverseUniform) = u.lengths
prob(u::inverseUniform, x) = (@assert length(x) == u.d; l = getLengths(u); prod([1/x[i]^2 * 1 / (l[i]) for i=1:u.d]))
logProb(u::inverseUniform, x) = (@assert length(x) == u.d; l = getLengths(u); sum([-2*log(x[i]) - log(l[i]) for i=1:u.d])  )#density function

#partialx(u::inverseUniform) = -2/x^3 * 1/(u.range[2]-u.range[1])

#struct univariateExponential <:priorType
#    range::Array
#    stdev::Float64
#    mean::Float64
#    function univariateExponential(range)
#
#    end
#end

max_stars_repo_name: dbindel/btg

max_issues_repo_name: dbindel/btg

max_forks_repo_name: dbindel/btg


text:
const PROMPT = ">> "
const REPL_PRELUDE = """

  ███╗   ███╗ ██████╗ ███╗   ██╗██╗  ██╗███████╗██╗   ██╗   |
  ████╗ ████║██╔═══██╗████╗  ██║██║ ██╔╝██╔════╝╚██╗ ██╔╝   |
  ██╔████╔██║██║   ██║██╔██╗ ██║█████╔╝ █████╗   ╚████╔╝    |
  ██║╚██╔╝██║██║   ██║██║╚██╗██║██╔═██╗ ██╔══╝    ╚██╔╝     |  Version $MONKEY_VERSION
  ██║ ╚═╝ ██║╚██████╔╝██║ ╚████║██║  ██╗███████╗   ██║      |
  ╚═╝     ╚═╝ ╚═════╝ ╚═╝  ╚═══╝╚═╝  ╚═╝╚══════╝   ╚═╝      |  BY $MONKEY_AUTHOR
"""
const REPL_FAREWELL = "Good bye!"
const _READY_TO_READ = Threads.Condition() # For test-use only.

function start_repl(; input::IO = stdin, output::IO = stdout, use_vm::Bool = false)
    # Handle SIGINT more elegantly
    Base.exit_on_sigint(false)

    env = use_vm ? nothing : Environment(; input = input, output = output)
    macro_env = Environment(; input = input, output = output)
    constants = use_vm ? Object[] : nothing
    globals = use_vm ? Object[] : nothing
    symbol_table = use_vm ? SymbolTable() : nothing

    if use_vm
        for (i, (name, _)) in enumerate(BUILTINS)
            define_builtin!(symbol_table, name, i - 1)
        end
    end

    println(output, REPL_PRELUDE)

    while true
        print(output, PROMPT)

        try
            line = readline(input; keep = true)

            # Ctrl-D (EOF) causes the REPL to stop
            if isempty(line)
                println(output, REPL_FAREWELL)
                break
            end

            l = Lexer(string(strip(line, '\n')))
            p = Parser(l)
            program = parse!(p)

            if !isempty(p.errors)
                println(
                    output,
                    ErrorObj(
                        "parser has $(length(p.errors)) error$(length(p.errors) == 1 ? "" : "s")",
                    ),
                )
                println(output, join(map(string, p.errors), "\n"))
                continue
            end

            program = define_macros!(macro_env, program)

            try
                expanded = expand_macros(program, macro_env)

                if use_vm
                    syntax_check_result =
                        analyze(expanded; existing_symbol_table = symbol_table)
                    if isa(syntax_check_result, ErrorObj)
                        println(output, syntax_check_result)
                        continue
                    end

                    # There should be no compilation errors.
                    c = Compiler(symbol_table, constants)
                    compile!(c, expanded)

                    vm = VM(bytecode(c), globals; input = input, output = output)
                    result = run!(vm)
                    if !isnothing(result)
                        println(output, result)

                        # Fix dangling global symbols
                        if isa(result, ErrorObj)
                            to_fix = []

                            for (name, sym) in symbol_table.store
                                if sym.scope == GlobalScope && sym.index >= length(globals)
                                    push!(to_fix, name)
                                end
                            end

                            append!(
                                globals,
                                fill(
                                    _NULL,
                                    symbol_table.definition_count - length(globals),
                                ),
                            )
                            for name in to_fix
                                pop!(symbol_table.store, name)
                            end
                        end
                    end
                else
                    syntax_check_result = analyze(expanded; exisiting_env = env)
                    if isa(syntax_check_result, ErrorObj)
                        println(output, syntax_check_result)
                        continue
                    end

                    evaluated = evaluate(expanded, env)
                    if !isnothing(evaluated)
                        println(output, evaluated)
                    end
                end
            catch e
                if isa(e, StackOverflowError) # `StackOverflowError` does not have `:msg` field
                    println(output, ErrorObj("runtime error: stack overflow"))
                elseif hasproperty(e, :msg)
                    if occursin("macro error", e.msg)
                        println(output, ErrorObj(e.msg))
                    else
                        println(output, ErrorObj("runtime error: " * e.msg))
                    end
                else
                    println(output, ErrorObj("runtime error: unknown error"))
                end
            end
        catch e
            # Handle SIGINT elegantly
            # `e` should be an InterruptException, but there might be some edge cases
            if !isa(e, InterruptException)
                println(output, ErrorObj("unknown error"))
            end
            println(output, REPL_FAREWELL)
            break
        end
    end
end


text:
module NPZ

# NPZ file format is described in
# https://github.com/numpy/numpy/blob/v1.7.0/numpy/lib/format.py

using ZipFile
using Compat

export npzread, npzwrite

const NPYMagic = UInt8[0x93, 'N', 'U', 'M', 'P', 'Y']
const ZIPMagic = UInt8['P', 'K', 3, 4]
const Version = UInt8[1, 0]

const TypeMaps = [
	("b1", Bool),
	("i1", Int8),
	("i2", Int16),
	("i4", Int32),
	("i8", Int64),
	("u1", UInt8),
	("u2", UInt16),
	("u4", UInt32),
	("u8", UInt64),
	("f4", Float32),
	("f8", Float64),
	("c8", Complex64),
	("c16", Complex128),
]
Numpy2Julia = [s => t for (s, t) in TypeMaps]
Julia2Numpy = [t => s for (s, t) in TypeMaps]

# Julia2Numpy is a dictionary that uses Types as keys.
# This is problematic for precompilation because the
# hash of a Type changes everytime Julia is run.
# The hash of the keys when NPZ is precompiled will
# not be the same as when it is later run. This can
# be fixed by rehashing the Dict when the module is
# loaded.

if VERSION >= v"0.4.0"
	__init__() = Base.rehash!(Julia2Numpy)
end

readle(ios::IO, ::Type{UInt16}) = htol(read(ios, UInt16))

function writele(ios::IO, x::Vector{UInt8})
	n = write(ios, x)
	if n != length(x)
		error("short write")
	end
	n
end

writele(ios::IO, x::ASCIIString) = writele(ios, convert(Vector{UInt8}, x))
writele(ios::IO, x::UInt16) = writele(ios, reinterpret(UInt8, [htol(x)]))

function parsechar(s::ASCIIString, c::Char)
	if s[1] != c
		error("parsing header failed: expected character '$c', found '$(s[1])'")
	end
	s[2:end]
end

function parsestring(s::ASCIIString)
	s = parsechar(s, '\'')
	i = findfirst(s, '\'')
	if i == 0
		error("parsing header failed: malformed string")
	end
	s[1:i-1], s[i+1:end]
end

function parsebool(s::ASCIIString)
	if s[1:4] == "True"
		return true, s[5:end]
	elseif s[1:5] == "False"
		return false, s[6:end]
	end
	error("parsing header failed: excepted True or False")
end

function parseinteger(s::ASCIIString)
	i = findfirst(c -> !isdigit(c), s)
	n = parse(Int, s[1:i-1])
	if s[i] == 'L'
		i += 1
	end
	n, s[i:end]
end

function parsetuple(s::ASCIIString)
	s = parsechar(s, '(')
	tup = Int[]
	while true
		s = strip(s)
		if s[1] == ')'
			break
		end
		n, s = parseinteger(s)
		tup = [tup; n]
		s = strip(s)
		if s[1] == ')'
			break
		end
		s = parsechar(s, ',')
	end
	s = parsechar(s, ')')
	tup, s
end

function parsedtype(s::ASCIIString)
	dtype, s = parsestring(s)
	c, t = dtype[1], dtype[2:end]
	if c == '<'
		toh = ltoh
	elseif c == '>'
		toh = ntoh
	elseif c == '|'
		toh = identity
	else
		error("parsing header failed: unsupported endian character $c")
	end
	if !haskey(Numpy2Julia, t)
		error("parsing header failed: unsupported type $t")
	end
	(toh, Numpy2Julia[t]), s
end

type Header
	descr :: @compat(Tuple{Function, DataType})
	fortran_order :: Bool
	shape :: Vector{Int}
end

function parseheader(s::ASCIIString)
	s = parsechar(s, '{')

	dict = @compat Dict{ASCIIString,Any}()
	for _ in 1:3
		s = strip(s)
		key, s = parsestring(s)
		s = strip(s)
		s = parsechar(s, ':')
		s = strip(s)
		if key == "descr"
			dict[key], s = parsedtype(s)
		elseif key == "fortran_order"
			dict[key], s = parsebool(s)
		elseif key == "shape"
			dict[key], s = parsetuple(s)
		else
			error("parsing header failed: bad dictionary key")
		end
		s = strip(s)
		if s[1] == '}'
			break
		end
		s = parsechar(s, ',')
	end
	s = strip(s)
	s = parsechar(s, '}')
	s = strip(s)
	if s != ""
		error("malformed header")
	end
	Header(dict["descr"], dict["fortran_order"], dict["shape"])
end

function npzreadarray(f::IO)
	b = read(f, UInt8, length(NPYMagic))
	if b != NPYMagic
		error("not a numpy array file")
	end
	b = read(f, UInt8, length(Version))
	if b != Version
		error("unsupported NPZ version")
	end
	hdrlen = readle(f, UInt16)
	hdr = ascii(read(f, UInt8, hdrlen))
	hdr = parseheader(strip(hdr))

	toh, typ = hdr.descr
	if hdr.fortran_order
		x = map(toh, read(f, typ, hdr.shape...))
	else
		x = map(toh, read(f, typ, reverse(hdr.shape)...))
		if ndims(x) > 1
			x = permutedims(x, collect(ndims(x):-1:1))
		end
	end
	x
end

function npzread(filename::AbstractString)
	# Detect if the file is a numpy npy array file or a npz/zip file.
	f = open(filename)
	b = read(f, UInt8, max(length(NPYMagic), length(ZIPMagic)))
	if startswith(b, ZIPMagic)
		close(f)
		f = ZipFile.Reader(filename)
		data = npzread(f)
		close(f)
		return data
	end
	if startswith(b, NPYMagic)
		seekstart(f)
		data = npzreadarray(f)
		close(f)
		return data
	end
	error("not a NPY or NPZ/Zip file: $filename")
end

function npzread(dir::ZipFile.Reader)
	vars = Dict{UTF8String,Any}()
	for f in dir.files
		name = f.name
		if endswith(name, ".npy")
			name = name[1:end-4]
		end
		vars[name] = npzreadarray(f)
	end
	vars
end

function npzwritearray(f::IO, x::Array{UInt8}, T::DataType, shape::Vector{Int})
	if !haskey(Julia2Numpy, T)
		error("unsupported type $T")
	end
	writele(f, NPYMagic)
	writele(f, Version)

	descr =  (ENDIAN_BOM == 0x01020304 ? ">" : "<") * Julia2Numpy[T]
	dict = "{'descr': '$descr', 'fortran_order': True, 'shape': $(tuple(shape...)), }"

	# The dictionary is padded with enough whitespace so that
	# the array data is 16-byte aligned
	n = length(NPYMagic)+length(Version)+2+length(dict)
	pad = (div(n+16-1, 16)*16) - n
	if pad > 0
		dict *= " "^(pad-1) * "\n"
	end

	writele(f, @compat UInt16(length(dict)))
	writele(f, dict)
	if write(f, x) != length(x)
		error("short write")
	end
end

function npzwritearray{T}(f::IO, x::Array{T})
	npzwritearray(f, reinterpret(UInt8, x[:]), T, [i for i in size(x)])
end

function npzwritearray{T<:Number}(f::IO, x::T)
	npzwritearray(f, reinterpret(UInt8, [x]), T, Int[])
end

function npzwrite(filename::AbstractString, x)
	f = open(filename, "w")
	npzwritearray(f, x)
	close(f)
end

function npzwrite{S<:AbstractString}(filename::AbstractString, vars::Dict{S,Any})
	dir = ZipFile.Writer(filename)
	for (k, v) in vars
		f = ZipFile.addfile(dir, k * ".npy")
		npzwritearray(f, v)
		close(f)
	end
	close(dir)
end

end	# module


text:
module Velocimetry

export prana

# Check whether we're running in a CI environment (can't use MATLAB)
const isCI = parse(Bool, lowercase(get(ENV, "CI", "false")))

if !isCI
    try
        using MATLAB
    catch e
        errstr = """Unable to initialize the MATLAB engine.
                    Check that the MATLAB binary is included in your PATH."""
        @error errstr exception=e
    end
else
    @eval Velocimetry, macro mat_str(expr) end
end

include("init.jl")

"""
    prana()

Launches the MATLAB-based prana interface. Requires a
working MATLAB installation and successful initialization
of the MATLAB.jl Julia-MATLAB interface package.
"""
prana() = mat"prana"

end


text:
using Base.Test
using HeavyGas
using Interpolations

for n in [1,2,3,4,10,11,100]
  for x in [0., 1., π]
    for r in [1., 11., sqrt(2)]
      @test length(HeavyGas.distribute_observers(x, r, n)) == 2*n+1
      @test HeavyGas.distribute_observers(x, r, n)[end÷2+1] ≈ x
    end
  end
end

od = ObserverData(0., 10., 10)
@test length(od.xstart) == 21
@test od.xstart[end÷2+1] ≈ 0.


text:
module LazyWAVFiles
    using WAV, LazyArrays
    export LazyWAVFile, DistributedWAVFile
    struct LazyWAVFile{T,N,S<:Tuple} <: AbstractArray{T,N}
        path::String
        size::S
    end
    function LazyWAVFile(path)
        r = wavread(path, format="native", subrange=1)[1]
        s = wavread(path, format="size")
        T = eltype(r)
        N = length(s[2])
        if N == 1
            s = (s[1],)
        end
        LazyWAVFile{T,N,typeof(s)}(path, s)
    end
    Base.size(f::LazyWAVFile) = f.size
    Base.size(f::LazyWAVFile{T,N},i) where {T,N} = i > N ? 1 : f.size[i]
    Base.length(f::LazyWAVFile) = prod(f.size)

    Base.getindex(f::LazyWAVFile{T,N}, i::Number) where {T,N} = wavread(f.path, format="native", subrange=i:i)[1][1]::T
    Base.getindex(f::LazyWAVFile{T,1}, i::AbstractRange) where {T} = vec(wavread(f.path, format="native", subrange=i)[1])::Array{T,1}
    Base.getindex(f::LazyWAVFile{T,2}, i::AbstractRange) where {T} = wavread(f.path, format="native", subrange=i)[1]::Array{T,2}

    Base.getindex(f::LazyWAVFile{T,1}, ::Colon) where {T} = vec(wavread(f.path, format="native")[1])::Array{T,1}
    Base.getindex(f::LazyWAVFile{T,2}, ::Colon) where {T} = wavread(f.path, format="native")[1]::Array{T,2}

    Base.eltype(f::LazyWAVFile{T}) where T = T
    Base.ndims(f::LazyWAVFile{T,N}) where {T,N} = N
    Base.show(io::IO, f::LazyWAVFile{T,N,S}) where {T,N,S} = println(io, "LazyWAV{$T, $N, $(f.size)}: ", f.path)

    struct DistributedWAVFile{T,N,L} <: AbstractArray{T,N}
        files::Vector{LazyWAVFile{T,N}}
        lazyarray::L
    end
    function DistributedWAVFile(folder::String)
        files = filter(readdir(folder)) do file
            file[end-2:end] == "wav"
        end
        files = sort(files)
        files = LazyWAVFile.(joinpath.(Ref(folder), files))
        DistributedWAVFile(files)
    end
    function DistributedWAVFile(files)
        lazyarray = Vcat(files...)
        DistributedWAVFile{eltype(files[1]), ndims(files[1]), typeof(lazyarray)}(files, lazyarray)
    end
    Base.length(f::DistributedWAVFile) = sum(length, f.files)
    Base.size(f::DistributedWAVFile{T,N}) where {T,N} = ntuple(i->sum(x->size(x,i), f.files), N)

    Base.show(io::IO, f::DistributedWAVFile{T,N}) where {T,N} = println(io, "DistributedWAVFile{$T, $N} with $(length(f.files)) files")

    Base.getindex(df::DistributedWAVFile, i...) = getindex(df.lazyarray, i...)

    Base.vcat(dfs::DistributedWAVFile...) = DistributedWAVFile(reduce(vcat, getfield.(dfs, :files)))

end


text:
# LS-RTM of the 2D Marmousi model using elastic average stochastic gradient descent
# Author: pwitte.slim@gmail.com
# Date: December 2018
#
# Warning: The examples requires ~40 GB of memory per shot if used without optimal checkpointing.
#

using Statistics, Random, LinearAlgebra, Distributed
using JUDI, SegyIO, HDF5, PyPlot

# Load migration velocity model
if ~isfile("$(JUDI.JUDI_DATA)/marmousi_model.h5")
    ftp_data("ftp://slim.gatech.edu/data/SoftwareRelease/Imaging.jl/2DLSRTM/marmousi_model.h5")
end
n, d, o, m0 = read(h5open("$(JUDI.JUDI_DATA)/marmousi_model.h5", "r"), "n", "d", "o", "m0")

# Set up model structure
model0 = Model((n[1], n[2]), (d[1], d[2]), (o[1], o[2]), m0)

# Load data
if ~isfile("$(JUDI.JUDI_DATA)/marmousi_2D.segy")
    ftp_data("ftp://slim.gatech.edu/data/SoftwareRelease/Imaging.jl/2DLSRTM/marmousi_2D.segy")
end
block = segy_read("$(JUDI.JUDI_DATA)/marmousi_2D.segy")
d_lin = judiVector(block)   # linearized observed data

# Set up wavelet
src_geometry = Geometry(block; key = "source", segy_depth_key = "SourceDepth")
wavelet = ricker_wavelet(src_geometry.t[1], src_geometry.dt[1], 0.03) # 30 Hz wavelet
q = judiVector(src_geometry, wavelet)

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

# Setup operators
opt = Options(optimal_checkpointing=true)  # ~40 GB of memory per source w/o checkpointing
M = judiModeling(model0, q.geometry, d_lin.geometry;options=opt)
J = judiJacobian(M, q)

# Right-hand preconditioners (model topmute)
Mr = judiTopmute(model0.n, 52, 10)

# Elastic average stochastic gradient descent
niter = 20
p = 10
batchsize = 1

eta = 0.03f0
rho = 1f0
alpha = eta*rho
beta = p*alpha

x = zeros(Float32, prod(model0.n).n, p)
xnew = zeros(Float32, prod(model0.n).n, p)
xav = zeros(Float32, prod(model0.n).n)

# Parallel gradient function
@everywhere function update_x(Ml, J, Mr, x, d, eta, alpha, xav)

    # gradient
    r = Ml*J*Mr*x - Ml*d
    g = adjoint(Mr)*adjoint(J)*adjoint(Ml)*r

    # Update variable
    return x - eta*g - alpha*(x - xav)
end
update_x_par = remote(update_x)     # parallel function instance

# Main loop
for j = 1: niter
    println("Iteration: ", j)

    @sync begin
        for k = 1: p

            # Select batch
            batchsize == 1 ? i = randperm(d_lin.nsrc)[1] : i = randperm(d_lin.nsrc)[1:batchsize]
            Ml = judiMarineTopmute2D(30, d_lin[i].geometry)    # data topmute

            # Calculate x update
            @async xnew[:, k] = update_x_par(Ml, J[i], Mr, x[:,k], d_lin[i], eta, alpha, xav)
        end
    end

    global xav = (1-beta)*xav + beta*(1/p *sum(x, dims=2))
    global x = copy(xnew)
end

# Save final velocity model, function value and history
h5open("lsrtm_marmousi_easgd_result.h5", "w") do file
    write(file, "x", reshape(xav, model0.n))
end

# Plot final image
figure(); imshow(copy(adjoint(reshape(xav, model0.n))), extent = (0, 7.99, 3.19, 0), cmap = "gray", vmin = -3e-2, vmax = 3e-2)
title("LS-RTM with elastic average SGD"); xlabel("Lateral position [km]"); ylabel("Depth [km]")


text:
function SimpleQsearch( gs::GameStatus, ply::Int, alpha::Int, beta::Int, depth::Float64, typeX::Int, InCheck::Bool, cutNode::Bool)
    # quiescence search
    val::Int = 0
    val2::Int = 0
    teban::Int = ((ply & 0x1) == 0)?gs.side:(gs.side$1)
    bestValue::Int = -Infinity
    ev_sign = ((ply & 0x01) == 0)?1:-1

    PvNode::Bool = (typeX == PV)

    if gs.timedout
        return 0
    end
    gs.triangularLength[ply+1] = ply
    if in_check( teban, gs.board)
        return SimplePVS( gs, ply, 1.0, alpha, beta, typeX, !cutNode)
    else
        bestValue = EvalBonanza( gs.side, gs.board, gs)

        if bestValue >= beta
            return bestValue
        end
        if (PvNode) && (bestValue > alpha)
            alpha = bestValue
        end
    end

    if (gs.inodes) & 1023 == 0
        now = time_ns()
        period::Int = now - gs.nsStart
        if period > MAXTHINKINGTIME
            gs.timedout = true
            return 0
        end
    end

    if float(ply) > (gs.depth + 3.0) # changed!
        return alpha
    end

    gs.MoveBeginIndex = gs.moveBufLen[ply+1]
    gs.moveBufLen[ply+1+1] = generateQBB(gs.board, gs.moveBuf, teban, gs.moveBufLen[ply+1], gs)

    # if gs.moveBufLen[ply+2] == 0 # added by T.K. 20130430 23:15
    #     return val
    # end
    beg = gs.moveBufLen[ply+1]+1
    for i = beg:gs.moveBufLen[ply+2]
        makeMove( gs.board, i, gs.moveBuf, teban)
        if in_check( teban, gs.board)||((gs.moveBuf[i].move & 0x00000300) == 0)
            #println("check!")
            takeBack( gs.board, i, gs.moveBuf, teban)
        else
	    gs.inodes += 1
	    val = -SimpleQsearch( gs, ply+1, -beta, -alpha, depth - 1.0, typeX, false,!cutNode)
            takeBack( gs.board, i, gs.moveBuf, teban)

            if val > bestValue
                bestValue = val
                if (val > alpha)
                    if (PvNode)&&(val < beta)
                        alpha = val
                        # both sides want to maximize from *their* perspective
                        gs.pvmovesfound += 1

                        gs.triangularArray[ply+1,ply+1] = gs.moveBuf[i]
		        # save this move
                        for j = (ply +1+1):gs.triangularLength[ply+1+1]
                            gs.triangularArray[ply+1,j] = gs.triangularArray[ply+1+1,j]
                            # and append the latest best PV from deeper plies
                        end
                        gs.triangularLength[ply+1] = gs.triangularLength[ply + 1+1]
                        rememberPV(gs)
                    else
                        return val
                    end
                end
            end
        end
    end
    bestValue
end

function SimplePVS( gs::GameStatus, ply::Int, depth::Float64, alpha::Int, beta::Int, typeX::Int, cutNode::Bool)

    PvNode = (typeX == PV)||(typeX == Root)
    RootNode = (typeX == Root)

    movesfound::Int = 0
    gs.pvmovesfound = 0
    teban::Int = ((ply & 0x1) == 0)?gs.side:gs.side$1
    bestValue::Int = -Infinity
    gs.triangularLength[ply+1] = ply
    ev_sign = ((ply & 0x01) == 0)?1:-1

    if (gs.inodes) & 1023 == 0
        now = time_ns()
        period::Int = now - gs.nsStart
        if period > MAXTHINKINGTIME
            gs.timedout = true
            return 0
        end
    end

    # 0.5手延長うまくいかない。qsearchがPVSをも一回呼ぶため。
    movesfound = 0
    gs.pvmovesfound = 0
    gs.MoveBeginIndex = gs.moveBufLen[ply+1]
    gs.moveBufLen[ply+1+1] = generateBB(gs.board, gs.moveBuf, teban, gs.moveBufLen[ply+1], gs)

    beg = gs.moveBufLen[ply+1]+1
    for i = beg:gs.moveBufLen[ply+2]
        selectmove( gs, ply, i, depth)
        makeMove( gs.board, i, gs.moveBuf, teban)
        ext::Float64 = 0.0
        if i == beg
            ext = 0.5
        end
        pvMove = PvNode && (i == beg)

        newDepth = depth - 1.0 + ext

        if in_check( teban, gs.board)
            #println("check!")
            takeBack( gs.board, i, gs.moveBuf, teban)
        else
	    gs.inodes += 1
	    movesfound += 1

            if (newDepth < 1.0)
                gs.followpv = false
            end

#            val = (newDepth < 1.0)? -SimpleQsearch( gs, ply+1, -(alpha+1), -alpha, 0.0, NonPV, false, !cutNode):-SimplePVS( gs, ply+1, newDepth, -(alpha+1), -alpha, NonPV, !cutNode)

#            if (PvNode && (PvNode || (val > alpha && (RootNode || value <beta))))
                if (newDepth < 1.0)
                    gs.followpv = false
                end
                val = (newDepth < 1.0)? -SimpleQsearch( gs, ply+1, -beta, -alpha, 0.0, PV, false, false):-SimplePVS( gs, ply+1, newDepth, -beta, -alpha, PV, false)
#            end

            takeBack( gs.board, i, gs.moveBuf, teban)

            if gs.timedout
                return 0
            end

            if val > bestValue
                bestValue = val

                if val > alpha
                    # both sides want to maximize from *their* perspective
                    gs.pvmovesfound += 1

                    gs.triangularArray[ply+1,ply+1] = gs.moveBuf[i]
	            # save this move
                    for j = (ply +1+1):gs.triangularLength[ply+1+1]
                        gs.triangularArray[ply+1,j] = gs.triangularArray[ply+1+1,j]
                        # and append the latest best PV from deeper plies
                    end
                    gs.triangularLength[ply+1] = gs.triangularLength[ply + 1+1]
                    rememberPV(gs)

                    if (PvNode)&&(val < beta)
                        alpha = val
                    else
                        if gs.board.nextMove == GOTE
                            gs.blackHeuristics[seeMoveFrom(gs.moveBuf[i])+1,seeMoveTo(gs.moveBuf[i])+1] += int(depth*depth)
                        else
                            gs.whiteHeuristics[seeMoveFrom(gs.moveBuf[i])+1,seeMoveTo(gs.moveBuf[i])+1] += int(depth*depth)
                        end
                        break
                    end
                end
                if bestValue >= beta
                    if gs.board.nextMove == GOTE
                        gs.blackHeuristics[seeMoveFrom(gs.moveBuf[i])+1,seeMoveTo(gs.moveBuf[i])+1] += int(depth*depth)
                    else
                        gs.whiteHeuristics[seeMoveFrom(gs.moveBuf[i])+1,seeMoveTo(gs.moveBuf[i])+1] += int(depth*depth)
                    end
                    break
                end
            end
        end
    end

    if gs.pvmovesfound > 0
        if gs.board.nextMove == GOTE
            gs.blackHeuristics[seeMoveFrom(gs.triangularArray[ply+1,ply+1])+1,seeMoveTo(gs.triangularArray[ply+1,ply+1])+1] += int(depth*depth)
        else
            gs.whiteHeuristics[seeMoveFrom(gs.triangularArray[ply+1,ply+1])+1,seeMoveTo(gs.triangularArray[ply+1,ply+1])+1] += int(depth*depth)
        end
    end
    if movesfound == 0
	if in_check(teban, gs.board)
            return (-Infinity + ply-1)
        end
    end

    bestValue
end

#end # @iprofile

max_stars_repo_name: kimrin/JapaneseChess

max_issues_repo_name: kimrin/JapaneseChess

max_forks_repo_name: kimrin/JapaneseChess


text:
# test hashing
begin
    @test hash(Clado("",[1 2],1,["A"],["B"])) ==
          hash(Clado("",[1 2],1,["A"],["B"]))

    @test hash(Phylo("",[1 2],1,["A"],[1],["B"],-1.0)) ==
          hash(Phylo("",[1 2],1,["A"],[1],["B"],-1.0))
end

#test equality
begin
    @test isequal(Clado("",[1 2],1,["A"],["B"]),
                  Clado("",[1 2],1,["A"],["B"]))
    @test isequal(Phylo("",[1 2],1,["A"],[1],["B"],-1.0),
                  Phylo("",[1 2],1,["A"],[1],["B"],-1.0))
end

# test tree querying functions

clado = Clado("test",[5 1
                      5 2
                      5 6
                      6 3
                      6 4],2,
              ["A","B","C","D"],
              ["F","E"])

phylo =Phylo("test", [5 1
                      5 2
                      5 6
                      6 3
                      6 4],2,
             ["A","B","C","D"],
             [0.1,0.2,0.5,0.3,0.4],
             ["F","E"],
             -1.0)

#test getroot
begin
    @test getroot(clado.edge[:,2],clado.edge[:,1]) == 5
    @test getroot(phylo.edge[:,2],phylo.edge[:,1]) == 5
end

#test getkids
begin
    @test getkids(clado) == Array[[], [], [], [],
                                  [1,2,6],
                                  [3,4]]

    @test getkids(phylo) == Array[[], [], [], [],
                                  [1,2,6],
                                  [3,4]]
end