text:
#####################################################################
#                                                                   #
# This file provides functions for interfacing with pti .raw files  #
#                                                                   #
#####################################################################
using DataStructures

"""
    get_pti_sections()

Returns `Array` of the names of the sections, in the order that they
appear in a PTI file, v33+
"""
function get_pti_sections()::Array
    return ["CASE IDENTIFICATION", "BUS", "LOAD", "FIXED SHUNT", "GENERATOR", "BRANCH", "TRANSFORMER",
            "AREA INTERCHANGE", "TWO-TERMINAL DC", "VOLTAGE SOURCE CONVERTER", "IMPEDANCE CORRECTION",
            "MULTI-TERMINAL DC", "MULTI-SECTION LINE", "ZONE", "INTER-AREA TRANSFER", "OWNER",
            "FACTS CONTROL DEVICE", "SWITCHED SHUNT", "GNE DEVICE", "INDUCTION MACHINE"]
end

"""
    get_pti_dtypes(field_name)

Returns `OrderedDict` of data types for PTI file section given by `field_name`,
as enumerated by PSS/E Program Operation Manual
"""
function get_pti_dtypes(field_name::AbstractString)::OrderedDict
    transaction_dtypes = OrderedDict{String,Type}("IC" => Int64, "SBASE" => Float64, "REV" => Int64,
                                                  "XFRRAT" => Float64, "NXFRAT" => Float64, "BASFRQ" => Float64)

    bus_dtypes = OrderedDict{String,Type}("I" => Int64, "NAME" => String, "BASKV" => Float64,
                                    "IDE" => Int64, "AREA" => Int64, "ZONE" => Int64, "OWNER" => Int64,
                                    "VM" => Float64, "VA" => Float64,
                                    "NVHI" => Float64, "NVLO" => Float64,
                                    "EVHI" => Float64, "EVLO" => Float64)

    load_dtypes = OrderedDict{String,Type}("I" => Int64, "ID" => String, "STATUS" => Int64, "AREA" => Int64,
                                    "ZONE" => Int64, "PL" => Float64, "QL" => Float64, "IP" => Float64,
                                    "IQ" => Float64, "YP" => Float64, "YQ" => Float64, "OWNER" => Int64,
                                    "SCALE" => Int64, "INTRPT" => Int64)

    fixded_shunt_dtypes = OrderedDict{String,Type}("I" => Int64, "ID" => String, "STATUS" => Int64,
                                            "GL" => Float64, "BL" => Float64)

    generator_dtypes = OrderedDict{String,Type}("I" => Int64, "ID" => String, "PG" => Float64, "QG" => Float64,
                                         "QT" => Float64, "QB" => Float64, "VS" => Float64, "IREG" => Int64,
                                         "MBASE" => Float64, "ZR" => Float64, "ZX" => Float64, "RT" => Float64,
                                         "XT" => Float64, "GTAP" => Float64, "STAT" => Int64, "RMPCT" => Float64,
                                         "PT" => Float64, "PB" => Float64, "O1" => Int64, "F1" => Float64,
                                         "O2" => Int64, "F2" => Float64, "O3" => Int64, "F3" => Float64,
                                         "O4" => Int64, "F4" => Float64, "WMOD" => Int64, "WPF" => Float64)

    branch_dtypes = OrderedDict{String,Type}("I" => Int64, "J" => Int64, "CKT" => String, "R" => Float64, "X" => Float64,
                                      "B" => Float64, "RATEA" => Float64, "RATEB" => Float64, "RATEC" => Float64,
                                      "GI" => Float64, "BI" => Float64, "GJ" => Float64, "BJ" => Float64,
                                      "ST" => Int64, "MET" => Int64, "LEN" => Float64, "O1" => Int64, "F1" => Float64,
                                      "O2" => Int64, "F2" => Float64, "O3" => Int64, "F3" => Float64,
                                      "O4" => Int64, "F4" => Float64)

    transformer_3_dtypes = OrderedDict{String,Type}("I" => Int64, "J" => Int64, "K" => Int64, "CKT" => String,
                                           "CW" => Int64, "CZ" => Int64, "CM" => Int64, "MAG1" => Float64,
                                           "MAG2" => Float64, "NMETR" => Int64, "NAME" => String,
                                           "STAT" => Int64,
                                           "O1" => Int64, "F1" => Float64,
                                           "O2" => Int64, "F2" => Float64,
                                           "O3" => Int64, "F3" => Float64,
                                           "O4" => Int64,  "F4" => Float64,
                                           "VECGRP" => String,

                                           "R1-2" => Float64, "X1-2" => Float64, "SBASE1-2" => Float64,
                                           "R2-3" => Float64, "X2-3" => Float64, "SBASE2-3" => Float64,
                                           "R3-1" => Float64, "X3-1" => Float64, "SBASE3-1" => Float64,
                                           "VMSTAR" => Float64, "ANSTAR" => Float64,

                                           "WINDV1" => Float64, "NOMV1" => Float64, "ANG1" => Float64,
                                           "RATA1" => Float64, "RATB1" => Float64, "RATC1" => Float64,
                                           "COD1" => Int64, "CONT1" => Int64, "RMA1" => Float64, "RMI1" => Float64,
                                           "VMA1" => Float64, "VMI1" => Float64, "NTP1" => Float64, "TAB1" => Int64,
                                           "CR1" => Float64, "CX1" => Float64, "CNXA1" => Float64,

                                           "WINDV2" => Float64, "NOMV2" => Float64, "ANG2" => Float64,
                                           "RATA2" => Float64, "RATB2" => Float64, "RATC2" => Float64,
                                           "COD2" => Int64, "CONT2" => Int64, "RMA2" => Float64, "RMI2" => Float64,
                                           "VMA2" => Float64, "VMI2" => Float64, "NTP2" => Float64, "TAB2" => Int64,
                                           "CR2" => Float64, "CX2" => Float64, "CNXA2" => Float64,

                                           "WINDV3" => Float64, "NOMV3" => Float64, "ANG3" => Float64,
                                           "RATA3" => Float64, "RATB3" => Float64, "RATC3" => Float64,
                                           "COD3" => Int64, "CONT3" => Int64, "RMA3" => Float64, "RMI3" => Float64,
                                           "VMA3" => Float64, "VMI3" => Float64, "NTP3" => Float64, "TAB3" => Int64,
                                           "CR3" => Float64, "CX3" => Float64, "CNXA3" => Float64)

    transformer_2_dtypes = OrderedDict{String,Type}("I" => Int64, "J" => Int64, "K" => Int64, "CKT" => String,
                                           "CW" => Int64, "CZ" => Int64, "CM" => Int64, "MAG1" => Float64,
                                           "MAG2" => Float64, "NMETR" => Int64, "NAME" => String,
                                           "STAT" => Int64,
                                           "O1" => Int64, "F1" => Float64,
                                           "O2" => Int64, "F2" => Float64,
                                           "O3" => Int64, "F3" => Float64,
                                           "O4" => Int64,  "F4" => Float64,
                                           "VECGRP" => String,

                                           "R1-2" => Float64, "X1-2" => Float64, "SBASE1-2" => Float64,

                                           "WINDV1" => Float64, "NOMV1" => Float64, "ANG1" => Float64,
                                           "RATA1" => Float64, "RATB1" => Float64, "RATC1" => Float64,
                                           "COD1" => Int64, "CONT1" => Int64, "RMA1" => Float64, "RMI1" => Float64,
                                           "VMA1" => Float64, "VMI1" => Float64, "NTP1" => Float64, "TAB1" => Int64,
                                           "CR1" => Float64, "CX1" => Float64, "CNXA1" => Float64,

                                           "WINDV2" => Float64, "NOMV2" => Float64)

    area_interchange_dtypes = OrderedDict{String,Type}("I" => Int64, "ISW" => Int64,
                                                       "PDES" => Float64, "PTOL" => Float64,
                                                       "ARNAME" => String)

    two_terminal_line_dtypes = OrderedDict{String,Type}("NAME" => String, "MDC" => Int64, "RDC" => Float64,
                                                 "SETVL" => Float64, "VSCHD" => Float64, "VCMOD" => Float64,
                                                 "RCOMP" => Float64, "DELTI" => Float64, "METER" => String,
                                                 "DCVMIN" => Float64, "CCCITMX" => Int64, "CCCACC" => Float64,
                                                 "IPR" => Int64, "NBR" => Int64, "ANMXR" => Float64,
                                                 "ANMNR" => Float64, "RCR" => Float64, "XCR" => Float64,
                                                 "EBASR" => Float64, "TRR" => Float64, "TAPR" => Float64,
                                                 "TMXR" => Float64, "TMNR" => Float64, "STPR" => Float64,
                                                 "ICR" => Int64, "IFR" => Int64, "ITR" => Int64, "IDR" => String,
                                                 "XCAPR" => Float64, "IPI" => Int64, "NBI" => Int64,
                                                 "ANMXI" => Float64, "ANMNI" => Float64, "RCI" => Float64,
                                                 "XCI" => Float64, "EBASI" => Float64, "TRI" => Float64,
                                                 "TAPI" => Float64, "TMXI" => Float64, "TMNI" => Float64,
                                                 "STPI" => Float64, "ICI" => Int64, "IFI" => Int64,
                                                 "ITI" => Int64, "IDI" => String, "XCAPI" => Float64)

    vsc_line_dtypes = OrderedDict{String,Type}("NAME" => String, "MDC" => Int64, "RDC" => Float64,
                                               "O1" => Int64, "F1" => Float64,
                                               "O2" => Int64, "F2" => Float64,
                                               "O3" => Int64, "F3" => Float64,
                                               "O4" => Int64, "F4" => Float64)

    vsc_subline_dtypes = OrderedDict{String,Type}("IBUS" => Int64, "TYPE" => Int64, "MODE" => Int64,
                                                  "DCSET" => Float64, "ACSET" => Float64,
                                                  "ALOSS" => Float64, "BLOSS" => Float64, "MINLOSS" => Float64,
                                                  "SMAX" => Float64, "IMAX" => Float64, "PWF" => Float64,
                                                  "MAXQ" => Float64, "MINQ" => Float64,
                                                  "REMOT" => Int64, "RMPCT" => Float64)

    impedance_correction_dtypes = OrderedDict{String,Type}("I" => Int64, "T1" => Float64, "F1" => Float64,
                                                    "T2" => Float64, "F2" => Float64, "T3" => Float64, "F3" => Float64,
                                                    "T4" => Float64, "F4" => Float64, "T5" => Float64, "F5" => Float64,
                                                    "T6" => Float64, "F6" => Float64, "T7" => Float64, "F7" => Float64,
                                                    "T8" => Float64, "F8" => Float64, "T9" => Float64, "F9" => Float64,
                                                    "T10" => Float64, "F10" => Float64, "T11" => Float64, "F11" => Float64)

    multi_term_main_dtypes = OrderedDict{String,Type}("NAME" => String, "NCONV" => Int64, "NDCBS" => Int64, "NDCLN" => Int64,
                                              "MDC" => Int64, "VCONV" => Int64, "VCMOD" => Float64, "VCONVN" => Float64)

    multi_term_nconv_dtypes = OrderedDict{String,Type}("IB" => Int64, "N" => Int64, "ANGMX" => Float64, "ANGMN" => Float64,
                                              "RC" => Float64, "XC" => Float64, "EBAS" => Float64, "TR" => Float64,
                                              "TAP" => Float64, "TPMX" => Float64, "TPMN" => Float64, "TSTP" => Float64,
                                              "SETVL" => Float64, "DCPF" => Float64, "MARG" => Float64, "CNVCOD" => Int64)

    multi_term_ndcbs_dtypes = OrderedDict{String,Type}("IDC" => Int64, "IB" => Int64, "AREA" => Int64, "ZONE" => Int64,
                                              "DCNAME" => String, "IDC2" => Int64, "RGRND" => Float64, "OWNER" => Int64)

    multi_term_ndcln_dtypes = OrderedDict{String,Type}("IDC" => Int64, "JDC" => Int64, "DCCKT" => String, "MET" => Int64,
                                              "RDC" => Float64, "LDC" => Float64)

    multi_section_dtypes = OrderedDict{String,Type}("I" => Int64, "J" => Int64, "ID" => String, "MET" => Int64, "DUM1" => Int64,
                                             "DUM2" => Int64, "DUM3" => Int64, "DUM4" => Int64, "DUM5" => Int64,
                                             "DUM6" => Int64, "DUM7" => Int64, "DUM8" => Int64, "DUM9" => Int64)

    zone_dtypes = OrderedDict{String,Type}("I" => Int64, "ZONAME" => String)

    interarea_dtypes = OrderedDict{String,Type}("ARFROM" => Int64, "ARTO" => Int64, "TRID" => String, "PTRAN" => Float64)

    owner_dtypes = OrderedDict{String,Type}("I" => Int64, "OWNAME" => String)

    FACTS_dtypes = OrderedDict{String,Type}("NAME" => String, "I" => Int64, "J" => Int64, "MODE" => Int64, "PDES" => Float64,
                                     "QDES" => Float64, "VSET" => Float64, "SHMX" => Float64, "TRMX" => Float64,
                                     "VTMN" => Float64, "VTMX" => Float64, "VSMX" => Float64, "IMX" => Float64,
                                     "LINX" => Float64, "RMPCT" => Float64, "OWNER" => Int64, "SET1" => Float64,
                                     "SET2" => Float64, "VSREF" => Int64, "REMOT" => Int64, "MNAME" => String)

    switched_shunt_dtypes = OrderedDict{String,Type}("I" => Int64, "MODSW" => Int64, "ADJM" => Int64, "STAT" => Int64,
                                                     "VSWHI" => Float64, "VSWLO" => Float64, "SWREM" => Int64,
                                                     "RMPCT" => Float64, "RMIDNT" => String, "BINIT" => Float64,
                                                     "N1" => Int64, "B1" => Float64, "N2" => Int64, "B2" => Float64,
                                                     "N3" => Int64, "B3" => Float64, "N4" => Int64, "B4" => Float64,
                                                     "N5" => Int64, "B5" => Float64, "N6" => Int64, "B6" => Float64,
                                                     "N7" => Int64, "B7" => Float64, "N8" => Int64, "B8" => Float64)

    # TODO: Account for multiple lines in GNE Device entries
    gne_device_dtypes = OrderedDict{String,Type}("NAME" => String, "MODEL" => String, "NTERM" => Int64, "BUSi" => Int64,
                                                 "NREAL" => Int64, "NINTG" => Int64, "NCHAR" => Int64,

                                                 "STATUS" => Int64, "OWNER" => Int64, "NMETR" => Int64,

                                                 "REALi" => Float64,
                                                 "INTGi" => Int64,
                                                 "CHARi" => String)

    induction_machine_dtypes = OrderedDict{String,Type}("I" => Int64, "ID" => String, "STAT" => Int64, "SCODE" => Int64,
                                                        "DCODE" => Int64, "AREA" => Int64, "ZONE" => Int64, "OWNER" => Int64,
                                                        "TCODE" => Int64, "BCODE" => Int64, "MBASE" => Float64,
                                                        "RATEKV" => Float64, "PCODE" => Int64, "PSET" => Float64,
                                                        "H" => Float64, "A" => Float64, "B" => Float64, "D" => Float64,
                                                        "E" => Float64, "RA" => Float64, "XA" => Float64, "XM" => Float64,
                                                        "R1" => Float64, "X1" => Float64, "R2" => Float64, "X2" => Float64,
                                                        "X3" => Float64, "E1" => Float64, "SE1" => Float64, "E2" => Float64,
                                                        "SE2" => Float64, "IA1" => Float64, "IA2" => Float64, "XAMULT" => Float64)

    dtypes = Dict{String,OrderedDict}("BUS" => bus_dtypes,
                                      "LOAD" => load_dtypes,
                                      "FIXED SHUNT" => fixded_shunt_dtypes,
                                      "GENERATOR" => generator_dtypes,
                                      "BRANCH" => branch_dtypes,
                                      "TRANSFORMER TWO WINDING" => transformer_2_dtypes,
                                      "TRANSFORMER THREE WINDING" => transformer_3_dtypes,
                                      "AREA INTERCHANGE" => area_interchange_dtypes,
                                      "TWO-TERMINAL DC" => two_terminal_line_dtypes,
                                      "VOLTAGE SOURCE CONVERTER" => vsc_line_dtypes,
                                      "VOLTAGE SOURCE CONVERTER SUBLINES" => vsc_subline_dtypes,
                                      "IMPEDANCE CORRECTION" => impedance_correction_dtypes,
                                      "MULTI-TERMINAL DC" => multi_term_main_dtypes,
                                      "MULTI-TERMINAL DC NCONV" => multi_term_nconv_dtypes,
                                      "MULTI-TERMINAL DC NDCBS" => multi_term_ndcbs_dtypes,
                                      "MULTI-TERMINAL DC NDCLN" => multi_term_ndcln_dtypes,
                                      "MULTI-SELECTION" => multi_section_dtypes,
                                      "ZONE" => zone_dtypes,
                                      "INTER-AREA TRANSFER" => interarea_dtypes,
                                      "OWNER" => owner_dtypes,
                                      "FACTS CONTROL DEVICE" => FACTS_dtypes,
                                      "SWITCHED SHUNT" => switched_shunt_dtypes,
                                      "CASE IDENTIFICATION" => transaction_dtypes,
                                      "GNE DEVICE" => gne_device_dtypes,
                                      "INDUCTION MACHINE" => induction_machine_dtypes)

    return dtypes[field_name]
end

"""
    parse_line_element!(data, elements, section)

Parses a single "line" of data elements from a PTI file, as given by `elements`
which is an array of the line, typically split at `,`. Elements are parsed into
data types given by `section` and saved into `data::Dict`

"""
function parse_line_element!(data::Dict, elements::Array, section::AbstractString)
    for (field, dtype) in get_pti_dtypes(section)
        try
            element = shift!(elements)
        catch message
            if isa(message, ArgumentError)
                debug(LOGGER, "Have run out of elements in $section at $field")
                break
            end
        end

        if endswith(element, '\r')
            element = element[1:end-1]
        end

        if startswith(element, "'") && endswith(element, "'")
            dtype = String
            element = element[2:end - 1]
        end

        try
            if dtype != String
                data[field] = parse(dtype, element)
            else
                data[field] = element
            end

        catch message
            if isa(message, ParseError)
                data[field] = element
            else
                debug(LOGGER, "$section $field $dtype $element")
                error(LOGGER, message)
            end
        end
    end
end

"""
    add_section_data!(pti_data, section_data, section)

Adds `section_data::Dict`, which contains all parsed elements of a PTI file
section given by `section`, into the parent `pti_data::Dict`
"""
function add_section_data!(pti_data::Dict, section_data::Dict, section::AbstractString)
    try
        pti_data[section] = append!(pti_data[section], [deepcopy(section_data)])
    catch message
        if isa(message, KeyError)
            pti_data[section] = [deepcopy(section_data)]
        else
            error(LOGGER, message)
        end
    end
end

"""
    get_line_elements(line)

Uses regular expressions to extract all separate data elements from a line of
a PTI file and populate them into an `Array{String}`. Comments, typically
indicated at the end of a line with a `'/'` character, are also extracted
separately, and `Array{Array{String}, String}` is returned.
"""
function get_line_elements(line::AbstractString)::Array
    match_string = r"(-*\d*\.*\d+[eE]*-*\d*)|(\'[^\']*?\')|(\"[^\"]*?\")|(\w+)|\,(\s+)?\,|(\/.*)"
    matches = matchall(match_string, line)

    debug(LOGGER, "$line")
    debug(LOGGER, "$matches")

    elements = []
    comment = ""
    for item in matches
        if startswith(item, ',') && endswith(item, ',') && length(item) == 2
            elements = append!(elements, [""])
        elseif startswith(item, '/')
            comment = item
        else
            elements = append!(elements, [item])
        end
    end

    return [elements, comment]
end

"""
    parse_pti_data(data_string, sections)

Parse a PTI raw file into a `Dict`, given the `data_string` of the file and a
list of the `sections` in the PTI file (typically given by default by
`get_pti_sections()`.
"""
function parse_pti_data(data_string::String, sections::Array)
    data_lines = split(data_string, '\n')
    skip_lines = 0
    skip_sublines = 0
    subsection = ""

    pti_data = Dict{String,Array{Dict}}()

    section = shift!(sections)
    section_data = Dict{String,Any}()

    for (line_number, line) in enumerate(data_lines)
        debug(LOGGER, "$line_number: $line")

        (elements, comment) = get_line_elements(line)

        if length(elements) != 0 && elements[1] == "Q"
            break

        elseif length(elements) != 0 && elements[1] == "0" && line_number != 1
            if line_number == 4
                section = shift!(sections)
            end

            match_string = r"\s*END OF ([\w\s-]+) DATA(?:, BEGIN ([\w\s-]+) DATA)?"
            debug(LOGGER, "$comment")
            matches = match(match_string, comment)

            if !isa(matches, Void)
                guess_section = matches.captures[1]
            else
                guess_section = ""
            end

            if guess_section == section
                section = shift!(sections)
                continue
            else
                info(LOGGER, "At line $line_number, unexpected section: expected: $section, comment specified: $(guess_section)")
                section = shift!(sections)
                continue
            end
        else
            if line_number == 4
                section = shift!(sections)
                section_data = Dict{String,Any}()
            end

            if skip_lines > 0
                skip_lines -= 1
                continue
            end

            debug(LOGGER, join(["Section:", section], " "))
            if section ∉ ["CASE IDENTIFICATION","TRANSFORMER","VOLTAGE SOURCE CONVERTER","MULTI-TERMINAL DC","TWO-TERMINAL DC","GNE DEVICE"]
                section_data = Dict{String,Any}()
                parse_line_element!(section_data, elements, section)

            elseif section == "CASE IDENTIFICATION"
                if line_number == 1
                    parse_line_element!(section_data, elements, section)
                    try
                        if section_data["REV"] < 33
                            warn(LOGGER, "Version $(section_data["REV"]) of PTI format is unsupported, parser may not function correctly.")
                        end
                    catch message
                        if isa(message, KeyError)
                            error(LOGGER, "This file is unrecognized and cannot be parsed")
                        end
                    end
                else
                    section_data["Comment_Line_$(line_number - 1)"] = line
                end

                if line_number < 3
                    continue
                end

            elseif section == "TRANSFORMER"
                section_data = Dict{String,Any}()
                if length(split(data_lines[line_number + 1], ',')) == 3  && parse(Int64, split(line, ',')[3]) == 0 # two winding transformer
                    temp_section = "TRANSFORMER TWO WINDING"
                    elements = split(join(data_lines[line_number:line_number + 3], ','), ',')
                    skip_lines = 3
                elseif length(split(data_lines[line_number + 1], ',')) == 11 && parse(Int64, split(line, ',')[3]) != 0 # three winding transformer
                    temp_section = "TRANSFORMER THREE WINDING"
                    elements = split(join(data_lines[line_number:line_number + 4], ','), ',')
                    skip_lines = 4
                else
                    error(LOGGER, "Cannot detect type of Transformer")
                end

                parse_line_element!(section_data, elements, temp_section)

            elseif section == "VOLTAGE SOURCE CONVERTER"
                if length(split(line, ',')) == 11
                    section_data = Dict{String,Any}()
                    parse_line_element!(section_data, elements, section)
                    skip_sublines = 2
                    continue

                elseif skip_sublines > 0
                    skip_sublines -= 1

                    (elements, comment) = get_line_elements(line)
                    subsection_data = Dict{String,Any}()

                    for (field, dtype) in get_pti_dtypes("$section SUBLINES")
                        element = shift!(elements)
                        subsection_data[field] = parse(dtype, element)
                    end

                    try
                        section_data["CONVERTER BUSES"] = append!(section_data["CONVERTER BUSES"], [deepcopy(subsection_data)])
                    catch message
                        if isa(message, KeyError)
                            section_data["CONVERTER BUSES"] = [deepcopy(subsection_data)]
                            continue
                        else
                            error(LOGGER, message)
                        end
                    end
                end

            elseif section == "TWO-TERMINAL DC"
                section_data = Dict{String,Any}()
                if length(split(line, ',')) == 12
                    elements = split(join(data_lines[line_number:line_number + 2], ','), ',')
                    skip_lines = 2
                end

                parse_line_element!(section_data, elements, section)

            elseif section == "MULTI-TERMINAL DC"
                if skip_sublines == 0
                    section_data = Dict{String,Any}()
                    parse_line_element!(section_data, elements, section)

                    if section_data["NCONV"] > 0
                        skip_sublines = section_data["NCONV"]
                        subsection = "NCONV"
                        continue
                    elseif section_data["NDCBS"] > 0
                        skip_sublines = section_data["NDCBS"]
                        subsection = "NDCBS"
                        continue
                    elseif section_data["NDCLN"] > 0
                        skip_sublines = section_data["NDCLN"]
                        subsection = "NDCLN"
                        continue
                    end
                end

                if skip_sublines > 0
                    skip_sublines -= 1

                    subsection_data = Dict{String,Any}()

                    for (field, dtype) in get_pti_dtypes("$section $subsection")
                        element = shift!(elements)
                        if startswith(element, "'") && endswith(element, "'")
                            subsection_data[field] = element[2:end-1]
                        else
                            subsection_data[field] = parse(dtype, element)
                        end
                    end

                    try
                        section_data["$(subsection[2:end])"] = append!(section_data["$(subsection[2:end])"], [deepcopy(subsection_data)])
                        if skip_sublines > 0 && subsection != "NDCLN"
                            continue
                        end
                    catch message
                        if isa(message, KeyError)
                            section_data["$(subsection[2:end])"] = [deepcopy(subsection_data)]
                            if skip_sublines > 0 && subsection != "NDCLN"
                                continue
                            end
                        else
                            error(LOGGER, message)
                        end
                    end

                    if skip_sublines == 0 && subsection != "NDCLN"
                        if subsection == "NDCBS"
                            skip_sublines = section_data["NDCLN"]
                            subsection = "NDCLN"
                            continue
                        elseif subsection == "NCONV"
                            skip_sublines = section_data["NDCBS"]
                            subsection = "NDCBS"
                            continue
                        end
                    elseif skip_sublines == 0 && subsection == "NDCLN"
                        subsection = ""
                    else
                        continue
                    end
                end

            elseif section == "GNE DEVICE"
                # TODO: handle multiple lines of GNE Device
                warn(LOGGER, "GNE DEVICE parsing is not supported.")
            end
        end
        if subsection != ""
            debug(LOGGER, "appending data")
        end
        add_section_data!(pti_data, section_data, section)
    end

    return pti_data
end

"""
    parse_pti(filename)

Open PTI raw file given by `filename`, passing the file contents as a string
to the main PTI parser, returning a `Dict` of all the data parsed into the
proper types.
"""
function parse_pti(filename::String)::Dict
    data_string = readstring(open(filename))
    pti_data = parse_pti_data(data_string, get_pti_sections())

    return pti_data
end


text:
using Stheno: unbox, LazyPDMat, Xt_A_X, Xt_A_Y, Xt_invA_Y, Xt_invA_X
using Random, LinearAlgebra

@testset "covariance_matrices" begin

    let
        rng, N, P, Q = MersenneTwister(123456), 5, 6, 2
        B = randn(rng, N, N)
        A_ = B' * B + 1e-6I
        @test logdet(cholesky(A_)) ≈ logdet(A_)
        @test logdet(A_) == logdet(A_')
    end

    # Test that the AbstractArray interface works.
    let
        rng, N, P, Q = MersenneTwister(123456), 5, 6, 2
        B = randn(rng, N, N)
        Σ_ = B' * B + 1e-6I
        Σ = LazyPDMat(Σ_, 1e-12)

        @test size(Σ) == (N, N)
        @test getindex(Σ, 10) == getindex(Σ_, 10)
    end

    # Test strided matrix functionality.
    let
        # Set up some matrices.
        rng, N, P, Q = MersenneTwister(123456), 5, 6, 2
        B = randn(rng, N, N)
        A_ = B' * B + UniformScaling(1e-6)
        A = LazyPDMat(A_, 1e-12)
        x, X, Y = randn(rng, N), randn(rng, N, P), randn(rng, N, Q)

        # Check utility functionality.
        @test LazyPDMat(A) === A
        @test LazyPDMat(5.0) === 5.0
        @test unbox(A) === A_
        @test size(A) == size(A_)
        @test size(A, 1) == size(A_, 1)
        @test size(A, 2) == size(A_, 2)

        @test A == A
        @test A ≈ A

        # Test unary operations.
        @test logdet(A) ≈ logdet(A_)
        @test cholesky(A).U == cholesky(A_ + A.ϵ * I).U

        # Test binary operations.
        @test A + A isa LazyPDMat
        @test unbox(A + A) == A_ + A_
        @test A + 0.5I isa LazyPDMat
        @test A + (-0.5) * I isa Matrix
        @test unbox(A + 0.5I) == unbox(A) + 0.5I
        @test A * A isa LazyPDMat
        @test unbox(A * A) == A_ * A_
        @test map(+, A, A) isa LazyPDMat
        @test unbox(map(+, A, A)) == LazyPDMat(map(+, A_, A_))
        @test map(*, A, A) isa LazyPDMat
        @test unbox(map(*, A, A)) == map(*, unbox(A), unbox(A))
        @test map(*, A, A) isa LazyPDMat
        @test map(*, A, A) == LazyPDMat(map(*, A_, A_))
        @test broadcast(*, A, A) isa LazyPDMat
        @test broadcast(*, A, A) == LazyPDMat(A_ .* A_)

        # Specialised matrix operations.
        @test Xt_A_X(A, x) isa Real
        @test Xt_A_X(A, x) ≈ x' * Matrix(A) * x
        @test Xt_A_X(A, X) isa LazyPDMat
        @test Xt_invA_X(A, X) isa LazyPDMat
        @test Xt_invA_X(A, X[:, 1]) isa Real
        @test X' * A_ * X ≈ unbox(Xt_A_X(A, X))
        @test X' * A * Y ≈ Xt_A_Y(X, A, Y)
        @test X' * (A_ \ X) ≈ unbox(Xt_invA_X(A, X))
        @test X' * (A_ \ Y) ≈ Xt_invA_Y(X, A, Y)
        @test A_ \ X ≈ A \ X
    end

    # Test misc. operations.
    let
        rng, N, N′, D = MersenneTwister(123456), 7, 8, 4
        X, Y = randn(rng, D, N), randn(rng, D, N)

        # Construct PD matrix.
        B = randn(rng, D, D)
        A_ = B' * B + UniformScaling(1e-6)
        A = LazyPDMat(A_, 1e-12)

        @test Stheno.diag_AᵀA(X) ≈ diag(X'X)
        @test Stheno.diag_AᵀB(X, Y) ≈ diag(X'Y)

        @test Stheno.diag_Xᵀ_A_X(A, X) ≈ diag(Xt_A_X(A, X))
        @test Stheno.diag_Xᵀ_A_Y(X, A, Y) ≈ diag(Xt_A_Y(X, A, Y))

        @test Stheno.diag_Xᵀ_invA_X(A, X) ≈ diag(Xt_invA_X(A, X))
        @test Stheno.diag_Xᵀ_invA_Y(X, A, Y) ≈ diag(Xt_invA_Y(X, A, Y))

        @test transpose(A) === A
        @test adjoint(A) === A
    end

    let
        rng, N = MersenneTwister(123456), 13

        # Construct two PD matrices.
        A__, X__ = randn(rng, N, N), randn(rng, N, N)
        A_, X_ = A__' * A__ + 1e-9I, X__' * X__ + 1e-9I
        A, X = LazyPDMat(A_, 1e-12), LazyPDMat(X_, 1e-12)

        @test Stheno.Xtinv_A_Xinv(A, X) isa LazyPDMat
        @test Stheno.Xtinv_A_Xinv(A, X) ≈ X_' \ (A / X_)
    end
end

ext: jl


text:
#!/usr/bin/env julia

using Luxor, Random, Colors

Random.seed!(42)

using Test

function test_arc_two_points(fname)
    # paper size C
    Drawing("C", fname)
    origin()
    background(Colors.RGB(1, 1, 1))
    sethue("magenta")
    setopacity(0.6)
    setline(2)
    tiles = Tiler(1200, 1200, 8, 8, margin=20)
    for (pos, n) in tiles
        _, pt2, pt3 = ngon(pos, rand(10:tiles.tilewidth/2), 3, rand(0:pi/12:2pi), vertices = true)
        if n % 4 == 0
            pt3 *= 1.1 # test for points not on arc
        end
        randomhue()
        setdash("solid")
        if n % 2 == 0
            sethue("blue")
            arc2r(pos, pt2, pt3, :stroke)
        else
            sethue("cyan")
            carc2r(pos, pt2, pt3, :stroke)
        end
        sethue("magenta")
        arrow(pos, pt2)
        circle(pos, 2, :fill)
        circle(pt2, 3, :fill)
        # the point that may not be on the arc:
        sethue("grey30")
        setdash("dash")
        line(pos, pt3, :stroke)
        circle(pt3, 4, :fill)
    end
    @test finish() == true
end

fname = "arc-twopoints.pdf"
test_arc_two_points(fname)
println("...finished test: output in $(fname)")


text:
"""
    autoname(N)

Given a `N` generate a tuple of length N with :x,:y,:z or :x1,...:xn
"""
function autonames(N)
    if N == 1
        (:x,)
    elseif N == 2
        (:x, :y)
    elseif N == 3
        (:x, :y, :z)
    else
        ntuple(N) do i
            Symbol("x$i")
        end
    end
end

function replace_default_names(names, N)
    if names == :auto
        autonames(N)
    else
        names
    end
end

"""
    axisnames(grid::AbstractGrid; include_units=true)

Get the names of the axis of the input `grid`.
In the case of Unitful quantities, they can be excluded by setting `include_units` to `false`.
"""
function axisnames(grid::AbstractGrid; include_units=true)
    names = string.(propertynames(grid))
    if include_units && hasunit(grid)
        units = unitname.(grid)
        string.(names, (" (",), units, (")",))
    else
        names
    end
end


text:
struct Keyframe{T}
    t::Float64
    value::T
end

Keyframe(t::Real, value) = Keyframe(convert(Float64, t), value)

Base.:+(kf::Keyframe, t::Real) = Keyframe(kf.t + t, kf.value)
Base.:-(kf::Keyframe, t::Real) = Keyframe(kf.t - t, kf.value)
Base.:*(kf::Keyframe, stretch::Real) = Keyframe(kf.t * stretch, kf.value)
Base.:/(kf::Keyframe, compress::Real) = Keyframe(kf.t / compress, kf.value)

function validate_keyframe_times(kfs::Vector{Keyframe{T}}) where T

    if length(kfs) > 1
        for (k1, k2) in zip(kfs[1:end-1], kfs[2:end])
            if k2.t <= k1.t
                error("Keyframes are not ordered correctly, t=$(k1.t) before t2=$(k2.t)")
            end
        end
    end

    for k in kfs
        if isnan(k.t)
            error("t is NaN")
        end
    end

end


text:
function foo(x) if x 42 else "foo" end end

println(foo(true))
println(foo(false))

max_stars_repo_name: gabriel-doriath-dohler/pjulia

max_issues_repo_name: gabriel-doriath-dohler/pjulia

max_forks_repo_name: gabriel-doriath-dohler/pjulia


text:
fibber(pre, cur, n) = cur>4e6 ? n : fibber(cur, pre+cur, cur%2 == 1 ? n : n+cur)
println(fibber(1, 2, 0))

max_stars_repo_path: 002 - Even Fibonacci Numbers/002 - Even_Fibonacci_Numbers.jl

max_stars_repo_name: LanguageAdventures/Project-Euler-Julia

max_issues_repo_name: LanguageAdventures/Project-Euler-Julia

max_forks_repo_name: LanguageAdventures/Project-Euler-Julia


text:
# using Ipaper
# using Test

@testset "factor" begin
  probs = [0.90, 0.95, 0.99, 0.999, 0.9999]
  levs = factor(probs)

  n = Int(1e3)
  x = repeat([levs[1]], n)
  y = repeat([probs[1]], n)

  sizeof(x) < sizeof(y)
end

@testset "dir" begin
  files = dir(".", "\\.jl\$")
  @test length(files) > 0
end

@testset "duplicated" begin
  x = 1:1000 |> collect
  @test sum(duplicated(x)) == 0

  x = [1, 2, 1, 3]
  @test findall(duplicated(x)) == [3]
end

# using Test
@testset "stringr" begin
  x = "hello world!"
  @test gsub(x, "hello", "Hello") == "Hello world!"
  @test grepl(x, "!\$")
  @test grep(x, "!\$") == grep(x, "!\$")
end

# using StatsBase
# x = 1:4 |> collect
# w = [1 1 0.5 0.5]

# weighted_mean(x, w)
# weighted_sum(x, w)


text:
@testset "7.5.2 Inverse hyperbolic secant functions" begin
    (a, b, c, d, m, n, p, x, ) = @variables a b c d m n p x

    #= ::Package:: =#

    #= ::Title:: =#
    #=Integration*Problems*Involving*Inverse*Hyperbolic*Secants=#

    #= ::Section::Closed:: =#
    #=Integrands*of*the*form*x^m*asech(a+b*x)^n=#

    @test_int [x^3*asech(a + b*x), x, 8, -(((2 + 17*a^2)*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(12*b^4)) - (x^2*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(12*b^2) + (a*(a + b*x)*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(3*b^4) - (a^4*asech(a + b*x))/(4*b^4) + (1/4)*x^4*asech(a + b*x) + (a*(1 + 2*a^2)*atan((sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(a + b*x)))/(2*b^4)]
    @test_int [x^2*asech(a + b*x), x, 7, (5*a*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(6*b^3) - (x*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(6*b^2) + (a^3*asech(a + b*x))/(3*b^3) + (1/3)*x^3*asech(a + b*x) - ((1 + 6*a^2)*atan((sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(a + b*x)))/(6*b^3)]
    @test_int [x^1*asech(a + b*x), x, 6, -((sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(2*b^2)) - (a^2*asech(a + b*x))/(2*b^2) + (1/2)*x^2*asech(a + b*x) + (a*atan((sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(a + b*x)))/b^2]
    @test_int [x^0*asech(a + b*x), x, 4, ((a + b*x)*asech(a + b*x))/b - (2*atan(sqrt((1 - a - b*x)/(1 + a + b*x))))/b]
    @test_int [asech(a + b*x)/x^1, x, 14, asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - asech(a + b*x)*log(1 + ℯ^(2*asech(a + b*x))) + PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - (1/2)*PolyLog(2, -ℯ^(2*asech(a + b*x)))]
    @test_int [asech(a + b*x)/x^2, x, 5, -((b*asech(a + b*x))/a) - asech(a + b*x)/x + (2*b*atanh((sqrt(1 + a)*tanh((1/2)*asech(a + b*x)))/sqrt(1 - a)))/(a*sqrt(1 - a^2))]
    @test_int [asech(a + b*x)/x^3, x, 7, (b*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(2*a*(1 - a^2)*x) + (b^2*asech(a + b*x))/(2*a^2) - asech(a + b*x)/(2*x^2) - ((1 - 2*a^2)*b^2*atanh((sqrt(1 + a)*tanh((1/2)*asech(a + b*x)))/sqrt(1 - a)))/(a^2*(1 - a^2)^(3/2))]
    @test_int [asech(a + b*x)/x^4, x, 8, (b*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(6*a*(1 - a^2)*x^2) - ((2 - 5*a^2)*b^2*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x))/(6*a^2*(1 - a^2)^2*x) - (b^3*asech(a + b*x))/(3*a^3) - asech(a + b*x)/(3*x^3) + ((2 - 5*a^2 + 6*a^4)*b^3*atanh((sqrt(1 + a)*tanh((1/2)*asech(a + b*x)))/sqrt(1 - a)))/(3*a^3*(1 - a^2)^(5/2))]

    @test_int [x^2*asech(a + b*x)^2, x, 17, -(x/(3*b^2)) + (2*a*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x)*asech(a + b*x))/b^3 - ((a + b*x)*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x)*asech(a + b*x))/(3*b^3) + (a^3*asech(a + b*x)^2)/(3*b^3) + (1/3)*x^3*asech(a + b*x)^2 - (2*asech(a + b*x)*atan(ℯ^asech(a + b*x)))/(3*b^3) - (4*a^2*asech(a + b*x)*atan(ℯ^asech(a + b*x)))/b^3 + (2*a*log(a + b*x))/b^3 + (im*PolyLog(2, (-im)*ℯ^asech(a + b*x)))/(3*b^3) + (2*im*a^2*PolyLog(2, (-im)*ℯ^asech(a + b*x)))/b^3 - (im*PolyLog(2, im*ℯ^asech(a + b*x)))/(3*b^3) - (2*im*a^2*PolyLog(2, im*ℯ^asech(a + b*x)))/b^3]
    @test_int [x^1*asech(a + b*x)^2, x, 11, -((sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x)*asech(a + b*x))/b^2) - (a^2*asech(a + b*x)^2)/(2*b^2) + (1/2)*x^2*asech(a + b*x)^2 + (4*a*asech(a + b*x)*atan(ℯ^asech(a + b*x)))/b^2 - log(a + b*x)/b^2 - (2*im*a*PolyLog(2, (-im)*ℯ^asech(a + b*x)))/b^2 + (2*im*a*PolyLog(2, im*ℯ^asech(a + b*x)))/b^2]
    @test_int [x^0*asech(a + b*x)^2, x, 8, ((a + b*x)*asech(a + b*x)^2)/b - (4*asech(a + b*x)*atan(ℯ^asech(a + b*x)))/b + (2*im*PolyLog(2, (-im)*ℯ^asech(a + b*x)))/b - (2*im*PolyLog(2, im*ℯ^asech(a + b*x)))/b]
    @test_int [asech(a + b*x)^2/x^1, x, 17, asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - asech(a + b*x)^2*log(1 + ℯ^(2*asech(a + b*x))) + 2*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + 2*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - asech(a + b*x)*PolyLog(2, -ℯ^(2*asech(a + b*x))) - 2*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) - 2*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) + (1/2)*PolyLog(3, -ℯ^(2*asech(a + b*x)))]
    @test_int [asech(a + b*x)^2/x^2, x, 12, -((b*asech(a + b*x)^2)/a) - asech(a + b*x)^2/x + (2*b*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) - (2*b*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) + (2*b*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) - (2*b*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a*sqrt(1 - a^2))]
    @test_int [asech(a + b*x)^2/x^3, x, 23, (b^2*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x)*asech(a + b*x))/(a*(1 - a^2)*(a + b*x)*(1 - a/(a + b*x))) + (b^2*asech(a + b*x)^2)/(2*a^2) - asech(a + b*x)^2/(2*x^2) + (b^2*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) - (2*b^2*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) - (b^2*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) + (2*b^2*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) + (b^2*log(x/(a + b*x)))/(a^2*(1 - a^2)) + (b^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) - (2*b^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) - (b^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) + (2*b^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2))]

    @test_int [x^1*asech(a + b*x)^3, x, 16, -((3*asech(a + b*x)^2)/(2*b^2)) - (3*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x)*asech(a + b*x)^2)/(2*b^2) - (a^2*asech(a + b*x)^3)/(2*b^2) + (1/2)*x^2*asech(a + b*x)^3 + (6*a*asech(a + b*x)^2*atan(ℯ^asech(a + b*x)))/b^2 + (3*asech(a + b*x)*log(1 + ℯ^(2*asech(a + b*x))))/b^2 - (6*im*a*asech(a + b*x)*PolyLog(2, (-im)*ℯ^asech(a + b*x)))/b^2 + (6*im*a*asech(a + b*x)*PolyLog(2, im*ℯ^asech(a + b*x)))/b^2 + (3*PolyLog(2, -ℯ^(2*asech(a + b*x))))/(2*b^2) + (6*im*a*PolyLog(3, (-im)*ℯ^asech(a + b*x)))/b^2 - (6*im*a*PolyLog(3, im*ℯ^asech(a + b*x)))/b^2]
    @test_int [x^0*asech(a + b*x)^3, x, 10, ((a + b*x)*asech(a + b*x)^3)/b - (6*asech(a + b*x)^2*atan(ℯ^asech(a + b*x)))/b + (6*im*asech(a + b*x)*PolyLog(2, (-im)*ℯ^asech(a + b*x)))/b - (6*im*asech(a + b*x)*PolyLog(2, im*ℯ^asech(a + b*x)))/b - (6*im*PolyLog(3, (-im)*ℯ^asech(a + b*x)))/b + (6*im*PolyLog(3, im*ℯ^asech(a + b*x)))/b]
    @test_int [asech(a + b*x)^3/x^1, x, 20, asech(a + b*x)^3*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + asech(a + b*x)^3*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - asech(a + b*x)^3*log(1 + ℯ^(2*asech(a + b*x))) + 3*asech(a + b*x)^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + 3*asech(a + b*x)^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - (3/2)*asech(a + b*x)^2*PolyLog(2, -ℯ^(2*asech(a + b*x))) - 6*asech(a + b*x)*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) - 6*asech(a + b*x)*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) + (3/2)*asech(a + b*x)*PolyLog(3, -ℯ^(2*asech(a + b*x))) + 6*PolyLog(4, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))) + 6*PolyLog(4, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))) - (3/4)*PolyLog(4, -ℯ^(2*asech(a + b*x)))]
    @test_int [asech(a + b*x)^3/x^2, x, 14, -((b*asech(a + b*x)^3)/a) - asech(a + b*x)^3/x + (3*b*asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) - (3*b*asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) + (6*b*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) - (6*b*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) - (6*b*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a*sqrt(1 - a^2)) + (6*b*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a*sqrt(1 - a^2))]
    @test_int [asech(a + b*x)^3/x^3, x, 32, -((3*b^2*asech(a + b*x)^2)/(2*a^2*(1 - a^2))) + (3*b^2*sqrt((1 - a - b*x)/(1 + a + b*x))*(1 + a + b*x)*asech(a + b*x)^2)/(2*a*(1 - a^2)*(a + b*x)*(1 - a/(a + b*x))) + (b^2*asech(a + b*x)^3)/(2*a^2) - asech(a + b*x)^3/(2*x^2) + (3*b^2*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*(1 - a^2)) + (3*b^2*asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(2*a^2*(1 - a^2)^(3/2)) - (3*b^2*asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) + (3*b^2*asech(a + b*x)*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*(1 - a^2)) - (3*b^2*asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(2*a^2*(1 - a^2)^(3/2)) + (3*b^2*asech(a + b*x)^2*log(1 - (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) + (3*b^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*(1 - a^2)) + (3*b^2*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) - (6*b^2*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) + (3*b^2*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*(1 - a^2)) - (3*b^2*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) + (6*b^2*asech(a + b*x)*PolyLog(2, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) - (3*b^2*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) + (6*b^2*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 - sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2)) + (3*b^2*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*(1 - a^2)^(3/2)) - (6*b^2*PolyLog(3, (a*ℯ^asech(a + b*x))/(1 + sqrt(1 - a^2))))/(a^2*sqrt(1 - a^2))]

    #= ::Section::Closed:: =#
    #=Integrands*of*the*form*x^m*asech(a*x^n)=#

    @test_int [x^3*asech(sqrt(x)), x, 4, -((1 - x)/(4*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))) + (1 - x)^2/(4*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x)) - (3*(1 - x)^3)/(20*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x)) + (1 - x)^4/(28*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x)) + (1/4)*x^4*asech(sqrt(x))]
    @test_int [x^2*asech(sqrt(x)), x, 4, -((1 - x)/(3*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))) + (2*(1 - x)^2)/(9*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x)) - (1 - x)^3/(15*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x)) + (1/3)*x^3*asech(sqrt(x))]
    @test_int [x^1*asech(sqrt(x)), x, 4, -((1 - x)/(2*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))) + (1 - x)^2/(6*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x)) + (1/2)*x^2*asech(sqrt(x))]
    @test_int [x^0*asech(sqrt(x)), x, 3, -((1 - x)/(sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))) + x*asech(sqrt(x))]
    @test_int [asech(sqrt(x))/x^1, x, 7, asech(sqrt(x))^2 - 2*asech(sqrt(x))*log(1 + ℯ^(2*asech(sqrt(x)))) - PolyLog(2, -ℯ^(2*asech(sqrt(x))))]
    @test_int [asech(sqrt(x))/x^2, x, 5, (1 - x)/(2*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*x^(3/2)) - asech(sqrt(x))/x + (sqrt(1 - x)*atanh(sqrt(1 - x)))/(2*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))]
    @test_int [asech(sqrt(x))/x^3, x, 6, (1 - x)/(8*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*x^(5/2)) + (3*(1 - x))/(16*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*x^(3/2)) - asech(sqrt(x))/(2*x^2) + (3*sqrt(1 - x)*atanh(sqrt(1 - x)))/(16*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))]
    @test_int [asech(sqrt(x))/x^4, x, 7, (1 - x)/(18*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*x^(7/2)) + (5*(1 - x))/(72*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*x^(5/2)) + (5*(1 - x))/(48*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*x^(3/2)) - asech(sqrt(x))/(3*x^3) + (5*sqrt(1 - x)*atanh(sqrt(1 - x)))/(48*sqrt(-1 + 1/sqrt(x))*sqrt(1 + 1/sqrt(x))*sqrt(x))]

    @test_int [asech(1/x), x, 3, -(sqrt(-1 + x)*sqrt(1 + x)) + x*acosh(x)]

    @test_int [asech(a*x^n)/x, x, 7, asech(a*x^n)^2/(2*n) - (asech(a*x^n)*log(1 + ℯ^(2*asech(a*x^n))))/n - PolyLog(2, -ℯ^(2*asech(a*x^n)))/(2*n)]
    @test_int [asech(a*x^5)/x, x, 7, (1/10)*asech(a*x^5)^2 - (1/5)*asech(a*x^5)*log(1 + ℯ^(2*asech(a*x^5))) - (1/10)*PolyLog(2, -ℯ^(2*asech(a*x^5)))]

    #= ::Section::Closed:: =#
    #=Integrands*involving*inverse*hyperbolic*secants*of*exponentials=#

    @test_int [asech(c*ℯ^(a + b*x)), x, 7, asech(c*ℯ^(a + b*x))^2/(2*b) - (asech(c*ℯ^(a + b*x))*log(1 + ℯ^(2*asech(c*ℯ^(a + b*x)))))/b - PolyLog(2, -ℯ^(2*asech(c*ℯ^(a + b*x))))/(2*b)]

    #= ::Section::Closed:: =#
    #=Integrands*involving*exponentials*of*inverse*hyperbolic*secants=#

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*x^m*ℯ^asech(a*x^p)=#

    #= ::Subsubsection::Closed:: =#
    #=p>0=#

    @test_int [ℯ^asech(a*x)*x^4, x, 5, -((2*ℯ^asech(a*x)*x)/(15*a^4)) + x^2/(15*a^3) - (ℯ^asech(a*x)*x^3)/(15*a^2) + x^4/(20*a) + (1/5)*ℯ^asech(a*x)*x^5, x^4/(20*a) + (1/5)*ℯ^asech(a*x)*x^5 - (2*sqrt(1 - a*x))/(15*a^5*sqrt(1/(1 + a*x))) - (x^2*sqrt(1 - a*x))/(15*a^3*sqrt(1/(1 + a*x)))]
    @test_int [ℯ^asech(a*x)*x^3, x, 5, x^3/(12*a) + (1/4)*ℯ^asech(a*x)*x^4 - (x*sqrt(1 - a*x))/(8*a^3*sqrt(1/(1 + a*x))) + (sqrt(1/(1 + a*x))*sqrt(1 + a*x)*asin(a*x))/(8*a^4)]
    @test_int [ℯ^asech(a*x)*x^2, x, 3, -((ℯ^asech(a*x)*x)/(3*a^2)) + x^2/(6*a) + (1/3)*ℯ^asech(a*x)*x^3, x^2/(6*a) + (1/3)*ℯ^asech(a*x)*x^3 - sqrt(1 - a*x)/(3*a^3*sqrt(1/(1 + a*x)))]
    @test_int [ℯ^asech(a*x)*x^1, x, 4, x/(2*a) + (1/2)*ℯ^asech(a*x)*x^2 + (sqrt(1/(1 + a*x))*sqrt(1 + a*x)*asin(a*x))/(2*a^2)]
    @test_int [ℯ^asech(a*x)*x^0, x, 3, ℯ^asech(a*x)*x - asech(a*x)/a + log(x)/a, ℯ^asech(a*x)*x - (2*atanh(sqrt((1 - a*x)/(1 + a*x))))/a + log(x)/a]
    @test_int [ℯ^asech(a*x)/x^1, x, 5, -(2/(1 - sqrt((1 - a*x)/(1 + a*x)))) + 2*atan(sqrt((1 - a*x)/(1 + a*x))), -(1/(a*x)) - sqrt(1 - a*x)/(a*x*sqrt(1/(1 + a*x))) - sqrt(1/(1 + a*x))*sqrt(1 + a*x)*asin(a*x)]
    @test_int [ℯ^asech(a*x)/x^2, x, 6, -(ℯ^asech(a*x)/(2*x)) + a*atanh(sqrt((1 - a*x)/(1 + a*x))), 1/(2*a*x^2) - ℯ^asech(a*x)/x + sqrt(1 - a*x)/(2*a*x^2*sqrt(1/(1 + a*x))) + (1/2)*a*sqrt(1/(1 + a*x))*sqrt(1 + a*x)*atanh(sqrt(1 - a*x)*sqrt(1 + a*x))]
    @test_int [ℯ^asech(a*x)/x^3, x, 5, -(1/(3*a*x^3)) - (8*a^2*((1 - a*x)/(1 + a*x))^(3/2))/(3*(1 - (1 - a*x)/(1 + a*x))^3), 1/(6*a*x^3) - ℯ^asech(a*x)/(2*x^2) + sqrt(1 - a*x)/(6*a*x^3*sqrt(1/(1 + a*x))) + (a*sqrt(1 - a*x))/(3*x*sqrt(1/(1 + a*x)))]
    @test_int [ℯ^asech(a*x)/x^4, x, 8, 1/(12*a*x^4) - ℯ^asech(a*x)/(3*x^3) + sqrt(1 - a*x)/(12*a*x^4*sqrt(1/(1 + a*x))) + (a*sqrt(1 - a*x))/(8*x^2*sqrt(1/(1 + a*x))) + (1/8)*a^3*sqrt(1/(1 + a*x))*sqrt(1 + a*x)*atanh(sqrt(1 - a*x)*sqrt(1 + a*x))]
    @test_int [ℯ^asech(a*x)/x^5, x, 7, 1/(20*a*x^5) - ℯ^asech(a*x)/(4*x^4) + sqrt(1 - a*x)/(20*a*x^5*sqrt(1/(1 + a*x))) + (a*sqrt(1 - a*x))/(15*x^3*sqrt(1/(1 + a*x))) + (2*a^3*sqrt(1 - a*x))/(15*x*sqrt(1/(1 + a*x)))]
    @test_int [ℯ^asech(a*x)/x^6, x, 10, 1/(30*a*x^6) - ℯ^asech(a*x)/(5*x^5) + sqrt(1 - a*x)/(30*a*x^6*sqrt(1/(1 + a*x))) + (a*sqrt(1 - a*x))/(24*x^4*sqrt(1/(1 + a*x))) + (a^3*sqrt(1 - a*x))/(16*x^2*sqrt(1/(1 + a*x))) + (1/16)*a^5*sqrt(1/(1 + a*x))*sqrt(1 + a*x)*atanh(sqrt(1 - a*x)*sqrt(1 + a*x))]
    @test_int [ℯ^asech(a*x)/x^7, x, 9, 1/(42*a*x^7) - ℯ^asech(a*x)/(6*x^6) + sqrt(1 - a*x)/(42*a*x^7*sqrt(1/(1 + a*x))) + (a*sqrt(1 - a*x))/(35*x^5*sqrt(1/(1 + a*x))) + (4*a^3*sqrt(1 - a*x))/(105*x^3*sqrt(1/(1 + a*x))) + (8*a^5*sqrt(1 - a*x))/(105*x*sqrt(1/(1 + a*x)))]
    @test_int [ℯ^asech(a*x)/x^8, x, 12, 1/(56*a*x^8) - ℯ^asech(a*x)/(7*x^7) + sqrt(1 - a*x)/(56*a*x^8*sqrt(1/(1 + a*x))) + (a*sqrt(1 - a*x))/(48*x^6*sqrt(1/(1 + a*x))) + (5*a^3*sqrt(1 - a*x))/(192*x^4*sqrt(1/(1 + a*x))) + (5*a^5*sqrt(1 - a*x))/(128*x^2*sqrt(1/(1 + a*x))) + (5/128)*a^7*sqrt(1/(1 + a*x))*sqrt(1 + a*x)*atanh(sqrt(1 - a*x)*sqrt(1 + a*x))]

    #= Mathematica*8*is*unable*to*validate*some*of*the*following*antiderivatives. =#
    @test_int [ℯ^asech(a*x^2)*x^7, x, 6, x^6/(24*a) + (1/8)*ℯ^asech(a*x^2)*x^8 - (x^2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(16*a^3) + (sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*asin(a*x^2))/(16*a^4)]
    @test_int [ℯ^asech(a*x^2)*x^6, x, 5, (2*x^5)/(35*a) + (1/7)*ℯ^asech(a*x^2)*x^7 - (2*x*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(21*a^3) + (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.F(asin(sqrt(a)*x), -1))/(21*a^(7/2))]
    @test_int [ℯ^asech(a*x^2)*x^5, x, 4, x^4/(12*a) + (1/6)*ℯ^asech(a*x^2)*x^6 - sqrt(1 - a*x^2)/(6*a^3*sqrt(1/(1 + a*x^2))), x^4/(12*a) + (1/6)*ℯ^asech(a*x^2)*x^6 - (sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(6*a^3)]
    @test_int [ℯ^asech(a*x^2)*x^4, x, 7, (2*x^3)/(15*a) + (1/5)*ℯ^asech(a*x^2)*x^5 + (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.E(asin(sqrt(a)*x), -1))/(5*a^(5/2)) - (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.F(asin(sqrt(a)*x), -1))/(5*a^(5/2))]
    @test_int [ℯ^asech(a*x^2)*x^3, x, 5, x^2/(4*a) + (1/4)*ℯ^asech(a*x^2)*x^4 + (sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*asin(a*x^2))/(4*a^2)]
    @test_int [ℯ^asech(a*x^2)*x^2, x, 4, (2*x)/(3*a) + (1/3)*ℯ^asech(a*x^2)*x^3 + (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.F(asin(sqrt(a)*x), -1))/(3*a^(3/2))]
    @test_int [ℯ^asech(a*x^2)*x^1, x, 6, (1/2)*ℯ^asech(a*x^2)*x^2 - (sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*atanh(sqrt(1 - a^2*x^4)))/(2*a) + log(x)/a]
    @test_int [ℯ^asech(a*x^2)*x^0, x, 8, -(2/(a*x)) + ℯ^asech(a*x^2)*x - (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(a*x) - (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.E(asin(sqrt(a)*x), -1))/sqrt(a) + (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.F(asin(sqrt(a)*x), -1))/sqrt(a)]
    @test_int [ℯ^asech(a*x^2)/x^1, x, 5, -(1/(2*a*x^2)) - sqrt(1 - a*x^2)/(2*a*x^2*sqrt(1/(1 + a*x^2))) - (1/2)*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*asin(a*x^2), -(1/(2*a*x^2)) - (sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(2*a*x^2) - (1/2)*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*asin(a*x^2)]
    @test_int [ℯ^asech(a*x^2)/x^2, x, 5, 2/(3*a*x^3) - ℯ^asech(a*x^2)/x + (2*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(3*a*x^3) - (2/3)*sqrt(a)*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*Elliptic.F(asin(sqrt(a)*x), -1)]
    @test_int [ℯ^asech(a*x^2)/x^3, x, 7, 1/(4*a*x^4) - ℯ^asech(a*x^2)/(2*x^2) + (sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*sqrt(1 - a^2*x^4))/(4*a*x^4) + (1/4)*a*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*atanh(sqrt(1 - a^2*x^4))]

    #= ::Subsubsection:: =#
    #=p<0=#

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*x^m*ℯ^asech(a*x^p)*with*m*symbolic=#

    @test_int [ℯ^asech(a*x^3)*x^m, x, 4, -((3*x^(-2 + m))/(a*(2 + m - m^2))) + (ℯ^asech(a*x^3)*x^(1 + m))/(1 + m) - (3*x^(-2 + m)*sqrt(1/(1 + a*x^3))*sqrt(1 + a*x^3)*HypergeometricFunctions._₂F₁(1/2, (1/6)*(-2 + m), (4 + m)/6, a^2*x^6))/(a*(2 + m - m^2))]
    @test_int [ℯ^asech(a*x^2)*x^m, x, 4, -((2*x^(-1 + m))/(a*(1 - m^2))) + (ℯ^asech(a*x^2)*x^(1 + m))/(1 + m) - (2*x^(-1 + m)*sqrt(1/(1 + a*x^2))*sqrt(1 + a*x^2)*HypergeometricFunctions._₂F₁(1/2, (1/4)*(-1 + m), (3 + m)/4, a^2*x^4))/(a*(1 - m^2))]
    @test_int [ℯ^asech(a*x^1)*x^m, x, 4, x^m/(a*m*(1 + m)) + (ℯ^asech(a*x)*x^(1 + m))/(1 + m) + (x^m*sqrt(1/(1 + a*x))*sqrt(1 + a*x)*HypergeometricFunctions._₂F₁(1/2, m/2, (2 + m)/2, a^2*x^2))/(a*m*(1 + m))]
    @test_int [ℯ^asech(a/x^1)*x^m, x, 5, (ℯ^asech(a/x)*x^(1 + m))/(1 + m) - x^(2 + m)/(a*(2 + 3*m + m^2)) - (sqrt(1/(1 + a/x))*sqrt(1 + a/x)*x^(2 + m)*HypergeometricFunctions._₂F₁(1/2, (1/2)*(-2 - m), -(m/2), a^2/x^2))/(a*(2 + 3*m + m^2))]

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*x^m*ℯ^asech(a*x^p)*with*p*symbolic=#

    @test_int [ℯ^asech(a*x^p)*x^m, x, 4,  (ℯ^asech(a*x^p)*x^(1 + m))/(1 + m) + (p*x^(1 + m - p))/(a*(1 + m)*(1 + m - p)) + (p*x^(1 + m - p)*sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*HypergeometricFunctions._₂F₁(1/2, (1 + m - p)/(2*p), (1 + m + p)/(2*p), a^2*x^(2*p)))/(a*(1 + m)*(1 + m - p))]

    @test_int [ℯ^asech(a*x^p)*x^1, x, 4, (1/2)*ℯ^asech(a*x^p)*x^2 + (p*x^(2 - p))/(2*a*(2 - p)) + (p*x^(2 - p)*sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*HypergeometricFunctions._₂F₁(1/2, (1/2)*(-1 + 2/p), (1/2)*(1 + 2/p), a^2*x^(2*p)))/(2*a*(2 - p))]
    @test_int [ℯ^asech(a*x^p)*x^0, x, 4, ℯ^asech(a*x^p)*x + (p*x^(1 - p))/(a*(1 - p)) + (p*x^(1 - p)*sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*HypergeometricFunctions._₂F₁(1/2, (1/2)*(-1 + 1/p), (1 + p)/(2*p), a^2*x^(2*p)))/(a*(1 - p))]
    @test_int [ℯ^asech(a*x^p)/x^1, x, 6, -(1/(x^p*(a*p))) - sqrt(1 - a*x^p)/(x^p*(a*p*sqrt(1/(1 + a*x^p)))) - (sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*asin(a*x^p))/p, -(1/(x^p*(a*p))) - (sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*sqrt(1 - a^2*x^(2*p)))/(x^p*(a*p)) - (sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*acsc(1/(x^p*a)))/p]
    @test_int [ℯ^asech(a*x^p)/x^2, x, 4, -(ℯ^asech(a*x^p)/x) + (p*x^(-1 - p))/(a*(1 + p)) + (1/(a*(1 + p)))*(p*x^(-1 - p)*sqrt(1/(1 + a*x^p))*sqrt(1 + a*x^p)*HypergeometricFunctions._₂F₁(1/2, -((1 + p)/(2*p)), -((1 - p)/(2*p)), a^2*x^(2*p)))]

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*x^m*ℯ^(n*asech(a*x))=#

    #= ::Subsubsection::Closed:: =#
    #=n>0=#

    #= [ℯ^(2*asech(a*x))*x^m, x, 14, 0] =#

    @test_int [ℯ^(2*asech(a*x))*x^4, x, 9, (5*sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^2)/(4*a^5) + ((1 - a*x)*(1 + a*x)^4)/(5*a^5) + (sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^4*(5 - 6*sqrt((1 - a*x)/(1 + a*x))))/(10*a^5) + ((1 + a*x)*(4 - sqrt((1 - a*x)/(1 + a*x))))/(4*a^5) - ((1 + a*x)^3*(4 + 45*sqrt((1 - a*x)/(1 + a*x))))/(30*a^5) - atan(sqrt((1 - a*x)/(1 + a*x)))/(2*a^5)]
    @test_int [ℯ^(2*asech(a*x))*x^3, x, 8, -(x/a^3) + ((1 - a*x)*(1 + a*x)^3)/(4*a^4) + ((1 + a*x)^2*(3 - 8*sqrt((1 - a*x)/(1 + a*x))))/(6*a^4) + (sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^3*(4 - 3*sqrt((1 - a*x)/(1 + a*x))))/(6*a^4)]
    @test_int [ℯ^(2*asech(a*x))*x^2, x, 7, ((1 + a*x)*(1 - sqrt((1 - a*x)/(1 + a*x)))*(1 + sqrt((1 - a*x)/(1 + a*x))))/(2*a^3) - (sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^2*(1 + sqrt((1 - a*x)/(1 + a*x)))^3)/(6*a^3) + ((1 + a*x)^3*(1 + sqrt((1 - a*x)/(1 + a*x)))^4)/(12*a^3) - (2*atan(sqrt((1 - a*x)/(1 + a*x))))/a^3]
    @test_int [ℯ^(2*asech(a*x))*x^1, x, 8, -((1 + a*x)^2/(2*a^2)) + ((1 + a*x)*(1 + 2*sqrt((1 - a*x)/(1 + a*x))))/a^2 + (2*log(1 + a*x))/a^2 + (4*log(1 - sqrt((1 - a*x)/(1 + a*x))))/a^2]
    @test_int [ℯ^(2*asech(a*x))*x^0, x, 7, -x - 4/(a*(1 - sqrt((1 - a*x)/(1 + a*x)))) + (4*atan(sqrt((1 - a*x)/(1 + a*x))))/a]
    @test_int [ℯ^(2*asech(a*x))/x^1, x, 5, -(2/(1 - sqrt((1 - a*x)/(1 + a*x)))^2) + 2/(1 - sqrt((1 - a*x)/(1 + a*x))) - log(1 + a*x) - 2*log(1 - sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(2*asech(a*x))/x^2, x, 4, -((4*a)/(3*(1 - sqrt((1 - a*x)/(1 + a*x)))^3)) + (2*a)/(1 - sqrt((1 - a*x)/(1 + a*x)))^2]
    @test_int [ℯ^(2*asech(a*x))/x^3, x, 5, -(a^2/(1 - sqrt((1 - a*x)/(1 + a*x)))^4) + (2*a^2)/(1 - sqrt((1 - a*x)/(1 + a*x)))^3 - (3*a^2)/(2*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) + a^2/(2*(1 - sqrt((1 - a*x)/(1 + a*x)))) + (1/2)*a^2*atanh(sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(2*asech(a*x))/x^4, x, 4, -((4*a^3)/(5*(1 - sqrt((1 - a*x)/(1 + a*x)))^5)) + (2*a^3)/(1 - sqrt((1 - a*x)/(1 + a*x)))^4 - (7*a^3)/(3*(1 - sqrt((1 - a*x)/(1 + a*x)))^3) + (3*a^3)/(2*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) - a^3/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))) - a^3/(4*(1 + sqrt((1 - a*x)/(1 + a*x))))]
    @test_int [ℯ^(2*asech(a*x))/x^5, x, 5, -((2*a^4)/(3*(1 - sqrt((1 - a*x)/(1 + a*x)))^6)) + (2*a^4)/(1 - sqrt((1 - a*x)/(1 + a*x)))^5 - (3*a^4)/(1 - sqrt((1 - a*x)/(1 + a*x)))^4 + (8*a^4)/(3*(1 - sqrt((1 - a*x)/(1 + a*x)))^3) - (11*a^4)/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) + (3*a^4)/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))) - a^4/(8*(1 + sqrt((1 - a*x)/(1 + a*x)))^2) + a^4/(8*(1 + sqrt((1 - a*x)/(1 + a*x)))) + (1/4)*a^4*atanh(sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(2*asech(a*x))/x^6, x, 4, -((4*a^5)/(7*(1 - sqrt((1 - a*x)/(1 + a*x)))^7)) + (2*a^5)/(1 - sqrt((1 - a*x)/(1 + a*x)))^6 - (18*a^5)/(5*(1 - sqrt((1 - a*x)/(1 + a*x)))^5) + (4*a^5)/(1 - sqrt((1 - a*x)/(1 + a*x)))^4 - (35*a^5)/(12*(1 - sqrt((1 - a*x)/(1 + a*x)))^3) + (11*a^5)/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) - a^5/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))) - a^5/(12*(1 + sqrt((1 - a*x)/(1 + a*x)))^3) + a^5/(8*(1 + sqrt((1 - a*x)/(1 + a*x)))^2) - a^5/(4*(1 + sqrt((1 - a*x)/(1 + a*x))))]

    #= ::Subsubsection::Closed:: =#
    #=n<0=#

    #= [ℯ^(-asech(a*x))*x^m, x, 7, 0] =#

    @test_int [ℯ^(-asech(a*x))*x^4, x, 8, -(x/a^4) - (sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^5)/(5*a^5) + ((1 + a*x)^2*(9 + 4*sqrt((1 - a*x)/(1 + a*x))))/(6*a^5) + ((1 + a*x)^4*(5 + 16*sqrt((1 - a*x)/(1 + a*x))))/(20*a^5) - ((1 + a*x)^3*(15 + 17*sqrt((1 - a*x)/(1 + a*x))))/(15*a^5)]
    @test_int [ℯ^(-asech(a*x))*x^3, x, 7, -((sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^4)/(4*a^4)) + ((1 + a*x)*(8 + sqrt((1 - a*x)/(1 + a*x))))/(8*a^4) - ((1 + a*x)^2*(8 + 5*sqrt((1 - a*x)/(1 + a*x))))/(8*a^4) + ((1 + a*x)^3*(4 + 9*sqrt((1 - a*x)/(1 + a*x))))/(12*a^4) + atan(sqrt((1 - a*x)/(1 + a*x)))/(4*a^4)]
    @test_int [ℯ^(-asech(a*x))*x^2, x, 6, -(x/a^2) - (sqrt((1 - a*x)/(1 + a*x))*(1 + a*x)^3)/(3*a^3) + ((1 + a*x)^2*(3 + 4*sqrt((1 - a*x)/(1 + a*x))))/(6*a^3)]
    @test_int [ℯ^(-asech(a*x))*x^1, x, 5, ((1 + a*x)^2*(1 - sqrt((1 - a*x)/(1 + a*x)))^2)/(4*a^2) + ((1 + a*x)*(1 + sqrt((1 - a*x)/(1 + a*x))))/(2*a^2) + atan(sqrt((1 - a*x)/(1 + a*x)))/a^2]
    @test_int [ℯ^(-asech(a*x))*x^0, x, 6, -((sqrt((1 - a*x)/(1 + a*x))*(1 + a*x))/a) + log(1 + a*x)/a + (2*log(1 + sqrt((1 - a*x)/(1 + a*x))))/a]
    @test_int [ℯ^(-asech(a*x))/x^1, x, 5, -(2/(1 + sqrt((1 - a*x)/(1 + a*x)))) - 2*atan(sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(-asech(a*x))/x^2, x, 5, -(a/(1 + sqrt((1 - a*x)/(1 + a*x)))^2) + a/(1 + sqrt((1 - a*x)/(1 + a*x))) - a*atanh(sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(-asech(a*x))/x^3, x, 4, -(a^2/(2*(1 - sqrt((1 - a*x)/(1 + a*x))))) - (2*a^2)/(3*(1 + sqrt((1 - a*x)/(1 + a*x)))^3) + a^2/(1 + sqrt((1 - a*x)/(1 + a*x)))^2 - a^2/(2*(1 + sqrt((1 - a*x)/(1 + a*x))))]
    @test_int [ℯ^(-asech(a*x))/x^4, x, 5, -(a^3/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))^2)) + a^3/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))) - a^3/(2*(1 + sqrt((1 - a*x)/(1 + a*x)))^4) + a^3/(1 + sqrt((1 - a*x)/(1 + a*x)))^3 - a^3/(1 + sqrt((1 - a*x)/(1 + a*x)))^2 + a^3/(2*(1 + sqrt((1 - a*x)/(1 + a*x)))) - (1/4)*a^3*atanh(sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(-asech(a*x))/x^5, x, 4, -(a^4/(6*(1 - sqrt((1 - a*x)/(1 + a*x)))^3)) + a^4/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) - (3*a^4)/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))) - (2*a^4)/(5*(1 + sqrt((1 - a*x)/(1 + a*x)))^5) + a^4/(1 + sqrt((1 - a*x)/(1 + a*x)))^4 - (4*a^4)/(3*(1 + sqrt((1 - a*x)/(1 + a*x)))^3) + a^4/(1 + sqrt((1 - a*x)/(1 + a*x)))^2 - (3*a^4)/(8*(1 + sqrt((1 - a*x)/(1 + a*x))))]
    @test_int [ℯ^(-asech(a*x))/x^6, x, 5, -(a^5/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))^4)) + a^5/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))^3) - (3*a^5)/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) + a^5/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))) - a^5/(3*(1 + sqrt((1 - a*x)/(1 + a*x)))^6) + a^5/(1 + sqrt((1 - a*x)/(1 + a*x)))^5 - (13*a^5)/(8*(1 + sqrt((1 - a*x)/(1 + a*x)))^4) + (19*a^5)/(12*(1 + sqrt((1 - a*x)/(1 + a*x)))^3) - a^5/(1 + sqrt((1 - a*x)/(1 + a*x)))^2 + (3*a^5)/(8*(1 + sqrt((1 - a*x)/(1 + a*x)))) - (1/8)*a^5*atanh(sqrt((1 - a*x)/(1 + a*x)))]
    @test_int [ℯ^(-asech(a*x))/x^7, x, 4, -(a^6/(10*(1 - sqrt((1 - a*x)/(1 + a*x)))^5)) + a^6/(4*(1 - sqrt((1 - a*x)/(1 + a*x)))^4) - (5*a^6)/(12*(1 - sqrt((1 - a*x)/(1 + a*x)))^3) + (3*a^6)/(8*(1 - sqrt((1 - a*x)/(1 + a*x)))^2) - (5*a^6)/(16*(1 - sqrt((1 - a*x)/(1 + a*x)))) - (2*a^6)/(7*(1 + sqrt((1 - a*x)/(1 + a*x)))^7) + a^6/(1 + sqrt((1 - a*x)/(1 + a*x)))^6 - (19*a^6)/(10*(1 + sqrt((1 - a*x)/(1 + a*x)))^5) + (9*a^6)/(4*(1 + sqrt((1 - a*x)/(1 + a*x)))^4) - (11*a^6)/(6*(1 + sqrt((1 - a*x)/(1 + a*x)))^3) + a^6/(1 + sqrt((1 - a*x)/(1 + a*x)))^2 - (5*a^6)/(16*(1 + sqrt((1 - a*x)/(1 + a*x))))]

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*x^m*ℯ^(n*asech(a*x)) / (1-a^2*x^2)=#

    @test_int [(d*x)^m*ℯ^asech(c*x)/(1 - c^2*x^2), x, 5, ((d*x)^m*sqrt(1/(1 + c*x))*sqrt(1 + c*x)*HypergeometricFunctions._₂F₁(1/2, m/2, (2 + m)/2, c^2*x^2))/(c*m) + ((d*x)^m*HypergeometricFunctions._₂F₁(1, m/2, (2 + m)/2, c^2*x^2))/(c*m)]

    @test_int [x^4*ℯ^asech(c*x)/(1 - c^2*x^2), x, 8, -(x^2/(2*c^3)) - (2*sqrt(1 - c*x))/(3*c^5*sqrt(1/(1 + c*x))) - (x^2*sqrt(1 - c*x))/(3*c^3*sqrt(1/(1 + c*x))) - log(1 - c^2*x^2)/(2*c^5)]
    @test_int [x^3*ℯ^asech(c*x)/(1 - c^2*x^2), x, 7, -(x/c^3) - (x*sqrt(1 - c*x))/(2*c^3*sqrt(1/(1 + c*x))) + (sqrt(1/(1 + c*x))*sqrt(1 + c*x)*asin(c*x))/(2*c^4) + atanh(c*x)/c^4]
    @test_int [x^2*ℯ^asech(c*x)/(1 - c^2*x^2), x, 4, -(sqrt(1 - c*x)/(c^3*sqrt(1/(1 + c*x)))) - log(1 - c^2*x^2)/(2*c^3)]
    @test_int [x^1*ℯ^asech(c*x)/(1 - c^2*x^2), x, 5, (sqrt(1/(1 + c*x))*sqrt(1 + c*x)*asin(c*x))/c^2 + atanh(c*x)/c^2]
    @test_int [x^0*ℯ^asech(c*x)/(1 - c^2*x^2), x, 8, -((sqrt(1/(1 + c*x))*sqrt(1 + c*x)*atanh(sqrt(1 - c*x)*sqrt(1 + c*x)))/c) + log(x)/c - log(1 - c^2*x^2)/(2*c)]
    @test_int [ℯ^asech(c*x)/(x^1*(1 - c^2*x^2)), x, 5, -(1/(c*x)) - sqrt(1 - c*x)/(c*x*sqrt(1/(1 + c*x))) + atanh(c*x)]
    @test_int [ℯ^asech(c*x)/(x^2*(1 - c^2*x^2)), x, 9, -(1/(2*c*x^2)) - sqrt(1 - c*x)/(2*c*x^2*sqrt(1/(1 + c*x))) - (1/2)*c*sqrt(1/(1 + c*x))*sqrt(1 + c*x)*atanh(sqrt(1 - c*x)*sqrt(1 + c*x)) + c*log(x) - (1/2)*c*log(1 - c^2*x^2)]
    @test_int [ℯ^asech(c*x)/(x^3*(1 - c^2*x^2)), x, 8, -(1/(3*c*x^3)) - c/x - sqrt(1 - c*x)/(3*c*x^3*sqrt(1/(1 + c*x))) - (2*c*sqrt(1 - c*x))/(3*x*sqrt(1/(1 + c*x))) + c^2*atanh(c*x)]

    @test_int [x*(a*x*ℯ^asech(a*x) - 1)/(1 - a^2*x^2), x, 7, -(ℯ^asech(a*x)*x)/a, -(sqrt(1 - a*x)/(a^2*sqrt(1/(1 + a*x))))]

    #= ::Section::Closed:: =#
    #=Miscellaneous*integrands*involving*inverse*hyperbolic*secants=#

    @test_int [asech(a + b*x)/((a*d)/b + d*x), x, 8, asech(a + b*x)^2/(2*d) - (asech(a + b*x)*log(1 + ℯ^(2*asech(a + b*x))))/d - PolyLog(2, -ℯ^(2*asech(a + b*x)))/(2*d)]

    @test_int [x^3*asech(a + b*x^4), x, 5, ((a + b*x^4)*asech(a + b*x^4))/(4*b) - atan(sqrt((1 - a - b*x^4)/(1 + a + b*x^4)))/(2*b)]

    @test_int [x^(n-1)*asech(a + b*x^n), x, 5, ((a + b*x^n)*asech(a + b*x^n))/(b*n) - (2*atan(sqrt((1 - a - b*x^n)/(1 + a + b*x^n))))/(b*n)]
    end

max_stars_repo_path: test/7 Inverse hyperbolic functions/7.5 Inverse hyperbolic secant/7.5.2 Inverse hyperbolic secant functions.jl


text:
module CustomVertexGraphs
  using AbstractBijections
  using Dictionaries
  using Graphs

  export set_vertices

  import Graphs: src, dst, nv, vertices, has_vertex, ne, edges, has_edge, neighbors, outneighbors, inneighbors, all_neighbors, is_directed, add_edge!, add_vertex!, add_vertices!, induced_subgraph, adjacency_matrix, blockdiag, edgetype

  import Base: show, eltype, copy

  # TODO: restrict to `AbstractSimpleGraph` (graph with contiguous integer vertices)
  # and `InvVectorBijection`, a Bijection where the inverse is a `Vector` (maps a contiguous
  # space of integers to another space).
  # TODO: rename `parent_graph` to something more descriptive like `simple_graph`, `int_vertex_graph`, etc.
  struct CustomVertexGraph{V,G<:AbstractGraph,B<:AbstractBijection} <: AbstractGraph{V}
    parent_graph::G
    vertex_to_parent_vertex::B # Invertible map from the vertices to the parent vertices
    function CustomVertexGraph(parent_graph::G, vertex_to_parent_vertex::B) where {G<:AbstractGraph,B<:AbstractBijection}
      @assert issetequal(vertices(parent_graph), image(vertex_to_parent_vertex))
      V = domain_eltype(vertex_to_parent_vertex)
      return new{V,G,B}(parent_graph, vertex_to_parent_vertex)
    end
  end
  parent_graph(graph::CustomVertexGraph) = graph.parent_graph
  vertex_to_parent_vertex(graph::CustomVertexGraph) = graph.vertex_to_parent_vertex

  copy(graph::CustomVertexGraph) = CustomVertexGraph(copy(parent_graph(graph)), copy(vertex_to_parent_vertex(graph)))

  eltype(g::CustomVertexGraph{V}) where {V} = V

  # Convenient constructor
  set_vertices(graph::AbstractGraph, vertices) = CustomVertexGraph(graph, vertices)

  vertices(graph::CustomVertexGraph) = domain(vertex_to_parent_vertex(graph))

  parent_graph_type(::Type{<:CustomVertexGraph{<:Any,G}}) where {G} = G

  parent_vertices(graph::CustomVertexGraph) = vertices(parent_graph(graph))
  parent_edges(graph::CustomVertexGraph) = edges(parent_graph(graph))
  parent_edgetype(graph::CustomVertexGraph) = edgetype(parent_graph(graph))

  parent_vertex(graph::CustomVertexGraph, vertex) = vertex_to_parent_vertex(graph)[vertex]
  parent_edge(graph::CustomVertexGraph, edge) = parent_edgetype(graph)(parent_vertex(graph, src(edge)), parent_vertex(graph, dst(edge)))
  parent_vertices(graph::CustomVertexGraph, vertices) = [parent_vertex(graph, vertex) for vertex in vertices]
  parent_vertex_to_vertex(graph::CustomVertexGraph, parent_vertex) = vertices(graph)[parent_vertex]

  CustomVertexGraph(vertices::Vector{T}) where T = CustomVertexGraph{Graph{Int}}(vertices)
  CustomVertexDiGraph(vertices::Vector{T}) where T = CustomVertexGraph{DiGraph{Int}}(vertices)

  import Base: Pair, Tuple, show, ==, hash, eltype
  import Graphs: AbstractEdge, src, dst, reverse

  abstract type AbstractCustomVertexEdge{V} <: AbstractEdge{V} end
  struct CustomVertexEdge{V} <: AbstractCustomVertexEdge{V}
    src::V
    dst::V
  end

  CustomVertexEdge{T}(e::CustomVertexEdge{T}) where {T} = e

  CustomVertexEdge(t::Tuple) = CustomVertexEdge(t[1], t[2])
  CustomVertexEdge(p::Pair) = CustomVertexEdge(p.first, p.second)
  CustomVertexEdge{T}(p::Pair) where {T} = CustomVertexEdge(T(p.first), T(p.second))
  CustomVertexEdge{T}(t::Tuple) where {T} = CustomVertexEdge(T(t[1]), T(t[2]))

  eltype(::Type{<:ET}) where ET<:AbstractCustomVertexEdge{T} where T = T

  src(e::AbstractCustomVertexEdge) = e.src
  dst(e::AbstractCustomVertexEdge) = e.dst

  function show(io::IO, mime::MIME"text/plain", e::AbstractCustomVertexEdge)
    show(io, src(e))
    print(io, " => ")
    show(io, dst(e))
    return nothing
  end

  show(io::IO, edge::AbstractCustomVertexEdge) = show(io, MIME"text/plain"(), edge)

  # Conversions
  Pair(e::AbstractCustomVertexEdge) = Pair(src(e), dst(e))
  Tuple(e::AbstractCustomVertexEdge) = (src(e), dst(e))

  CustomVertexEdge{T}(e::AbstractCustomVertexEdge) where {T} = CustomVertexEdge{T}(T(e.src), T(e.dst))

  # Convenience functions
  reverse(e::T) where T<:AbstractCustomVertexEdge = T(dst(e), src(e))
  ==(e1::AbstractCustomVertexEdge, e2::AbstractCustomVertexEdge) = (src(e1) == src(e2) && dst(e1) == dst(e2))
  hash(e::AbstractCustomVertexEdge, h::UInt) = hash(src(e), hash(dst(e), h))

  edgetype(graph::CustomVertexGraph{V}) where {V} = CustomVertexEdge{V}

  default_vertices(graph::AbstractGraph) = Vector(vertices(graph))

  function CustomVertexGraph(graph::AbstractGraph, vertices=default_vertices(graph))
    if length(vertices) != nv(graph)
      throw(ArgumentError("Vertices and parent graph's vertices must have equal length."))
    end
    if !allunique(vertices)
      throw(ArgumentError("Vertices have to be unique."))
    end
    return CustomVertexGraph(graph, inv(Bijection(vertices)))
  end

  function CustomVertexGraph(graph::AbstractGraph, dims::Tuple{Vararg{Integer}})
    return CustomVertexGraph(graph, vec(Tuple.(CartesianIndices(dims))))
  end

  function CustomVertexGraph(dims::Tuple{Vararg{Integer}})
    return CustomVertexGraph(Graph(prod(dims)), vec(Tuple.(CartesianIndices(dims))))
  end

  function CustomVertexGraph{S}(vertices::Vector) where {S<:AbstractGraph}
    return CustomVertexGraph(S(length(vertices)), vertices)
  end

  has_vertex(g::CustomVertexGraph, v) = v in vertices(g)

  function edges(graph::CustomVertexGraph)
    vertex(parent_vertex) = inv(vertex_to_parent_vertex(graph))[parent_vertex]
    edge(parent_edge) = CustomVertexEdge(vertex(src(parent_edge)), vertex(dst(parent_edge)))
    return map(edge, parent_edges(graph))
  end

  for f in [:outneighbors, :inneighbors, :all_neighbors, :neighbors]
    @eval begin
      function $f(graph::CustomVertexGraph, v)
        parent_vertices = $f(parent_graph(graph), parent_vertex(graph, v))
        return [parent_vertex_to_vertex(graph, u) for u ∈ parent_vertices]
      end
    end
  end

  # Ambiguity errors with Graphs.jl
  for f in [
    :neighbors, :inneighbors, :outneighbors, :all_neighbors
  ]
    @eval begin
      $f(tn::CustomVertexGraph, vertex::Integer) = $f(parent_graph(tn), vertex)
    end
  end

  function add_edge!(graph::CustomVertexGraph, edge::CustomVertexEdge)
    add_edge!(parent_graph(graph), parent_edge(graph, edge))
    return graph
  end

  function has_edge(graph::CustomVertexGraph, edge::CustomVertexEdge)
    return has_edge(parent_graph(graph), parent_edge(graph, edge))
  end

  # handles single-argument edge constructors such as pairs and tuples
  has_edge(g::CustomVertexGraph, x) = has_edge(g, edgetype(g)(x))
  add_edge!(g::CustomVertexGraph, x) = add_edge!(g, edgetype(g)(x))

  # handles two-argument edge constructors like src,dst
  has_edge(g::CustomVertexGraph, x, y) = has_edge(g, edgetype(g)(x, y))
  add_edge!(g::CustomVertexGraph, x, y) = add_edge!(g, edgetype(g)(x, y))

  function add_vertex!(graph::CustomVertexGraph, v)
    if v ∈ vertices(graph)
      throw(ArgumentError("Duplicate vertices are not allowed"))
    end
    add_vertex!(parent_graph(graph))
    insert!(vertex_to_parent_vertex(graph), v, last(parent_vertices(graph)))
    return graph
  end

  function add_vertices!(graph::CustomVertexGraph, vertices::Vector)
    if any(v ∈ vertices(graph) for v ∈ vertices)
      throw(ArgumentError("Duplicate vertices are not allowed"))
    end
    for vertex in vertices
      add_vertex!(graph, vertex)
    end
    return graph
  end

  function induced_subgraph(graph::CustomVertexGraph, sub_vertices::Vector)
    return _induced_subgraph(graph, _get_vertices(graph, sub_vertices))
  end

  function _get_vertices(graph::CustomVertexGraph, vertex)
    return vertex
  end

  function _get_vertices(graph::CustomVertexGraph, vertices::Vector)
    return mapreduce(vertex -> _get_vertices(graph, vertex), vcat, vertices)
  end

  function _induced_subgraph(graph::CustomVertexGraph, vertices::Vector)
    sub_graph, _ = induced_subgraph(parent_graph(graph), parent_vertices(graph, vertices))
    return CustomVertexGraph(sub_graph, vertices), vertices
  end

  is_directed(LG::Type{<:CustomVertexGraph}) = is_directed(parent_graph_type(LG))

  function blockdiag(graph1::CustomVertexGraph, graph2::CustomVertexGraph)
    new_parent_graph = blockdiag(parent_graph(graph1), parent_graph(graph2))
    new_vertices = vcat(vertices(graph1), vertices(graph2))
    return CustomVertexGraph(new_parent_graph, new_vertices)
  end

  for f in [:nv, :ne, :adjacency_matrix]
    @eval begin
      $f(graph::CustomVertexGraph, args...) = $f(parent_graph(graph), args...)
    end
  end

  function show(io::IO, mime::MIME"text/plain", graph::CustomVertexGraph)
    println(io, "CustomVertexGraph with $(nv(graph)) vertices:")
    show(io, mime, vertices(graph))
    println(io, "\n")
    println(io, "and $(ne(graph)) edge(s):")
    for e in edges(graph)
      show(io, mime, e)
      println(io)
    end
    return nothing
  end

  show(io::IO, graph::CustomVertexGraph) = show(io, MIME"text/plain"(), graph)
end # module CustomVertexGraphs


text:
module MatrixCompletion

import Optim
import NLopt

export complete, cross_complete

function nuclear_norm{T <: AbstractFloat}(m::Matrix{T})
    f = svdfact(m)
    sum(f[:S])
end

function d_nuclear_norm{T <: AbstractFloat}(m::Matrix{T})
    # Alt (http://math.stackexchange.com/users/123685/alt), Derivative
    # of nuclear norm, URL (version: 2015-12-29):
    # http://math.stackexchange.com/q/701104
    f = svdfact(m)
    f[:U] * f[:Vt]
end

type CompletionResults{T <: AbstractFloat}
    method::Symbol
    initial::Matrix{T}
    minimum::Matrix{T}
    f_minimum::Float64
    xtol::T
    ftol::T
end

function complete{T <: AbstractFloat}(m::Matrix{T}, lambda::Real;
                                      method = :LD_LBFGS, tol = eps(T),
                                      x0 = 0.5 * m + mean(m),
                                      maxeval = Inf, maxtime = Inf)
    sz = size(m)

    mones = zeros(sz)
    for i = eachindex(m)
        if m[i] != 0.
            mones[i] = 1.
        end
    end

    function f(vx::Vector, grad::Vector)
        x = reshape(vx, sz)

        fn = 0.
        for i = eachindex(m)
            s = mones[i] * (x[i] - m[i])
            fn += s * s
        end
        fn = sqrt(fn)

        f = svdfact(x)
        sum(f[:S]) + lambda * fn
    end

    function g!(vx::Vector, grad::Vector)
        x = reshape(vx, sz)
        z = reshape(grad, sz)

        fn = 0.
        for i = eachindex(m)
            s = mones[i] * (x[i] - m[i])
            z[i] = s
            fn += s * s
        end
        fn = sqrt(fn)

        f = svdfact(x)
        BLAS.gemm!('N', 'N', 1., f[:U], f[:Vt], lambda / fn, z)
    end

    function fg!(vx::Vector, grad::Vector)
        x = reshape(vx, sz)
        z = reshape(grad, sz)

        # z = mones .* (x - m)
        # fn = vecnorm(z)
        # grad[:] = vec(d_nuclear_norm(x) + (lambda/fn) * z)
        # nuclear_norm(x) + lambda * fn

        fn = 0.
        for i = eachindex(m)
            s = mones[i] * (x[i] - m[i])
            z[i] = s
            fn += s * s
        end
        fn = sqrt(fn)

        f = svdfact(x)
        BLAS.gemm!('N', 'N', 1., f[:U], f[:Vt], lambda / fn, z)
        x = sum(f[:S]) + lambda * fn

        x
    end

    d4 = Optim.DifferentiableFunction(f, g!, fg!)
    res = Optim.optimize(d4, vec(x0))
    optf = res.f_minimum
    optx = res.minimum

    # opt = NLopt.Opt(method, length(m))
    # NLopt.min_objective!(opt, fg!)
    # NLopt.xtol_rel!(opt, tol)
    # NLopt.ftol_rel!(opt, sqrt(tol))

    # if maxeval < Inf
    #     NLopt.maxeval!(opt, maxeval)
    # end
    # if maxtime < Inf
    #     NLopt.maxtime!(opt, maxeval)
    # end

    # (optf,optx,ret) = NLopt.optimize(opt, vec(x0))

    CompletionResults(method, m, reshape(optx, sz), optf, tol, sqrt(tol))
end

function roundn(v, n::Int)
    round(v * 10. ^ n) * 10. ^ (-n)
end

function cross_complete(m; n=5, js=1:n,
                        lambda_min = 0, lambda_max = 20,
                        trace = false)
    subset = rand(1:n, size(m))

    insample = map(j -> subset .!= j, js)
    outsample = map(j -> ! insample[j], js)

    m_in  = map(j -> m .* insample[j], js)

    if trace
        cnt = countnz(m)
        for j = js
            cnt_in = countnz(insample[j] .* m)
            cnt_out = countnz(outsample[j] .* m)

            println("j = ", j)
            println("insample count: ", cnt_in, " / ", cnt, " = ", roundn(cnt_in / cnt, 2))
            println("outsample count: ", cnt_out, " / ", cnt, " = ", roundn(cnt_out / cnt, 2))
            println()
        end
    end

    function x_utility(lambda)
        function j_utility(j)
            # @time r = complete(m_in, lambda, x0=res.minimum)
            # r = complete(m_in[j], lambda, x0=res[j].minimum)
            @time r = complete(m_in[j], lambda)
            u = vecnorm((m - r.minimum) .* outsample[j])

            x = reshape(r.minimum, size(m))
            f = svdfact(x)
            println(j, " : ", @sprintf("%.2f", lambda), " : ", round(Int, f[:S]))

            u
        end

        us = map(j_utility, js)
        u = mean(us)

        if trace
            println(@sprintf("%.2f", u), " ", roundn(us, 2))
            println()
        end

        u
    end

    Optim.optimize(x_utility, lambda_min, lambda_max, rel_tol = 1e-4)
end

end # module


text:
# test to compare allGen and only disruption gen
using Distributed;
addprocs(20);
@everywhere include("loadMod.jl");
@everywhere const GUROBI_ENV = Gurobi.Env();

N = 5;
dataList = Dict();

caseList = [13,33,123];
T = 96;
τ = Int64(1/6*T);
Δt = 0.25;
pathTrain = load("pathHist_600.jld");

for ci in 1:length(caseList)
    pathDict = pathTrain["pathDict"][ci][T];
    for j in procs()
        remotecall_fetch(readInData,j,ci,caseList,T,τ);
    end

    cutDict,LBHist,UBHist,UBuHist,UBlHist,timeHist = solveMain(T, Δt, 30, false,false, 2, 2);

    startT = time();
    cutDict,LBHist,UBHist,UBuHist,UBlHist,timeHist = solveMain(T, Δt, N, false, false,
        max(Int64(round(500/N)),20), max(Int64(round(500/N)),20), Dict(), false, 200, [], 0, pathDict);
    elapsedT = time() - startT;
    dataList["dOnly"] = [LBHist,UBHist,UBuHist,UBlHist,timeHist,elapsedT];

    save("dOnlyResults_$(ci).jld","data",dataList);
end


text:
export LinearProg
module LinearProg

# solve Kattis problem "https://open.kattis.com/problems/maxflow" using linear optimization

export ixedge, modeldata

using JuMP
import Clp

ixedge(i, j, n) = (2n - i) * (i - 1) ÷ 2 + j - i

function modeldata(model, n, (ii, jj, aa), s, t)
    m = length(ii)
    @assert m == length(jj) == length(aa)
    x = Dict()
    ex = [AffExpr(0.0) for i = 1:n]
    for k = 1:m
        i, j, a = ii[k], jj[k], aa[k]
        @assert 0 <= i < j < n
        @assert a >= 0.0
        xij = @variable(model, lower_bound=0, upper_bound=a)
        set_name(xij, "x[$i,$j]")
        x[i,j] = xij
        add_to_expression!(ex[i+1], 1.0, xij)
        add_to_expression!(ex[j+1], -1.0, xij)
    end
    @objective(model, Max, ex[s+1])
    con = Vector{Any}(undef, n - 2)
    j = 0
    for k = 1:n
        if !(k-1 in (s, t))
            j += 1
            con[j] = @constraint(model, ex[k] == 0)
        end
    end
    model
end

function main(io::IO...)
    n, s, t, ii, jj, aa = read_data(io...)
    run(n, s, t, ii, jj, aa)
end

function run(n, s, t, ii, jj, aa)
    model = Model()
    set_optimizer(model, Clp.Optimizer)
    set_optimizer_attribute(model, MOI.Silent(), true)
    modeldata(model, n, (ii, jj, aa), s, t)
    print(model)
    optimize!(model)
    # solution_summary(model)
    # println(termination_status(model))
    # println(objective_value(model))
    print_result(n, model)
end

function read_data(io::IO=stdin)
    line = split(readline(io))
    n, m, s, t = parse.(Int, line)
    ii, jj, aa = Vector{Int}.(undef, (m, m, m))
    for k = 1:m
        i, j, a = parse.(Int, split(readline(io)))
        ii[k] = i
        jj[k] = j
        aa[k] = a
    end
    n, s, t, ii, jj, aa
end

function print_result(n, model)
    var = all_variables(model)
    val = value.(var)
    m = count(val .!= 0)
    println("$n $(Int(objective_value(model))) $m")
    for l = 1:length(var)
        a = Int(round(val[l]))
        a == 0 && continue
        i, j = var2ij(var[l])
        println("$i $j $a")
    end
    nothing
end

function var2ij(var)
    str = split(split(split(string(var), '[')[2], ']')[1], ',')
    parse.(Int, str)
end

end


text:
#!/usr/bin/env julia

using Printf

# What is interesting in Julia is the @printf macro vs
# the println function. In addition to the use of the '@'
# prefix, println uses standard open and close parenthesis
# where @printf doesn't.

println("Hello, world!")

@printf "Hello, world with print macro!\n"

max_stars_repo_name: wbeebe/julia

max_issues_repo_name: wbeebe/julia

max_forks_repo_name: wbeebe/julia


text:
# Stores the details of a node within a representation graph.
type RepresentationGraphNode
  label::AbstractString
  parent::AbstractString
  clean::Bool
  lamarckian::Bool
  destinations::Vector{RepresentationGraphNode}
  sources::Vector{RepresentationGraphNode}
  can_reach::Vector{RepresentationGraphNode}
  can_reach_from::Vector{RepresentationGraphNode}

  # Creates a new representation graph node from a given species stage.
  RepresentationGraphNode(s::SpeciesStage) =
    RepresentationGraphNode(s.label, s.parent, false, s.lamarckian)

  # Creates a new child node using a given label, a parent node, a clean flag
  # and a lamarckian flag.
  RepresentationGraphNode(label::AbstractString, parent::AbstractString, clean::Bool, lamarckian::Bool) =
    new(label, parent, clean, lamarckian, [], [], [], [])
end

# Produces an (unprepared) clone of a given representation graph node.
copy(n::RepresentationGraphNode) =
  RepresentationGraphNode(n.label, n.parent, n.clean, n.lamarckian)

# Checks whether a given node within a representation graph is the root node.
isroot(n::RepresentationGraphNode) = n.parent == ""


text:
using TrajectoryOptimization
using Random
using BenchmarkTools
Random.seed!(7)
### Solver options ###
dt = 0.1
opts = TrajectoryOptimization.SolverOptions()
opts.square_root = false
opts.verbose = false
opts.cache = false
opts.c1 = 1e-8
opts.c2 = 10.0
opts.cost_tolerance_intermediate = 1e-4
opts.constraint_tolerance = 1e-4
opts.cost_tolerance = 1e-4
opts.iterations_outerloop = 50
opts.iterations = 250
opts.iterations_linesearch = 25
opts.constraint_decrease_ratio = 0.25
opts.penalty_scaling = 10.0
opts.bp_reg_initial = 0.0
opts.outer_loop_update_type = :individual
opts.use_static = false
opts.resolve_feasible = false
opts.λ_second_order_update = false
opts.bp_reg_type = :control
######################

### Set up model, objective, solver ###
# Model, objective (unconstrained)
model_pendulum, obj_uncon_pendulum = TrajectoryOptimization.Dynamics.pendulum!
model_dubins, obj_uncon_dubins = TrajectoryOptimization.Dynamics.dubinscar!
model_cartpole, obj_uncon_cartpole = TrajectoryOptimization.Dynamics.cartpole_udp

## Constraints

# pendulum
u_min_pendulum = -2
u_max_pendulum = 2
x_min_pendulum = [-20;-20]
x_max_pendulum = [20; 20]

# dubins car
u_min_dubins = [-1; -1]
u_max_dubins = [1; 1]
x_min_dubins = [0; -100; -100]
x_max_dubins = [1.0; 100; 100]

# cartpole
u_min_cartpole = -20
u_max_cartpole = 40
x_min_cartpole = [-10; -1000; -1000; -1000]
x_max_cartpole = [10; 1000; 1000; 1000]

# -Constrained objective
obj_con_pendulum = ConstrainedObjective(obj_uncon_pendulum, u_min=u_min_pendulum, u_max=u_max_pendulum, x_min=x_min_pendulum, x_max=x_max_pendulum)
obj_con_dubins = ConstrainedObjective(obj_uncon_dubins, u_min=u_min_dubins, u_max=u_max_dubins, x_min=x_min_dubins, x_max=x_max_dubins)
obj_con_cartpole = ConstrainedObjective(obj_uncon_cartpole, u_min=u_min_cartpole, u_max=u_max_cartpole, x_min=x_min_cartpole, x_max=x_max_cartpole)

# Solver
intergrator = :rk3_foh
solver_pendulum = Solver(model_pendulum,obj_con_pendulum,integration=intergrator,dt=dt,opts=opts)
solver_dubins = Solver(model_dubins,obj_con_dubins,integration=intergrator,dt=dt,opts=opts)
solver_cartpole = Solver(model_cartpole,obj_con_cartpole,integration=intergrator,dt=dt,opts=opts)

# -Initial state and control trajectories
X_interp_pendulum = line_trajectory(solver_pendulum.obj.x0,solver_pendulum.obj.xf,solver_pendulum.N)
X_interp_dubins = line_trajectory(solver_dubins.obj.x0,solver_dubins.obj.xf,solver_dubins.N)
X_interp_cartpole = line_trajectory(solver_cartpole.obj.x0,solver_cartpole.obj.xf,solver_cartpole.N)

U_pendulum = rand(solver_pendulum.model.m,solver_pendulum.N)
U_dubins = rand(solver_dubins.model.m,solver_dubins.N)
U_cartpole = rand(solver_cartpole.model.m,solver_cartpole.N)

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

### Solve ###
@time results_pendulum, stats_pendulum = solve(solver_pendulum,U_pendulum)
@time results_dubins, stats_dubins = solve(solver_dubins,U_dubins)
@time results_cartpole, stats_cartpole = solve(solver_cartpole,U_cartpole)

### Results ###
println("Final state (pendulum)-> res: $(results_pendulum.X[end]), goal: $(solver_pendulum.obj.xf)\n Iterations: $(stats_pendulum["iterations"])\n Outer loop iterations: $(stats_pendulum["major iterations"])\n Max violation: $(stats_pendulum["c_max"][end])\n Max μ: $(maximum([to_array(results_pendulum.MU)[:]; results_pendulum.μN[:]]))\n Max abs(λ): $(maximum(abs.([to_array(results_pendulum.LAMBDA)[:]; results_pendulum.λN[:]])))\n")
println("Final state (dubins)-> res: $(results_dubins.X[end]), goal: $(solver_dubins.obj.xf)\n Iterations: $(stats_dubins["iterations"])\n Outer loop iterations: $(stats_dubins["major iterations"])\n Max violation: $(stats_dubins["c_max"][end])\n Max μ: $(maximum([to_array(results_dubins.MU)[:]; results_dubins.μN[:]]))\n Max abs(λ): $(maximum(abs.([to_array(results_dubins.LAMBDA)[:]; results_dubins.λN[:]])))\n")
println("Final state (cartpole)-> res: $(results_cartpole.X[end]), goal: $(solver_cartpole.obj.xf)\n Iterations: $(stats_cartpole["iterations"])\n Outer loop iterations: $(stats_cartpole["major iterations"])\n Max violation: $(stats_cartpole["c_max"][end])\n Max μ: $(maximum([to_array(results_cartpole.MU)[:]; results_cartpole.μN[:]]))\n Max abs(λ): $(maximum(abs.([to_array(results_cartpole.LAMBDA)[:]; results_cartpole.λN[:]])))\n")


text:
module console

export console_height,
        console_width,
        cursor_position,
        up,
        beginning_previous_line,
        prev_line,
        next_line,
        down,
        clear,
        hide_cursor,show_cursor,line,
        erase_line,
        cleartoend,
        move_to_line,
        change_scroll_region,
        savecursor,
        restorecursor

const STDOUT = stdout
const STDERR = stderr

# ---------------------------------------------------------------------------- #
#                                CURSOR CONTROL                                #
# ---------------------------------------------------------------------------- #
"""
Save the current cursor position
"""
savecursor(io::IO=stdout) = write(io, "\e[s")

"""
Restore a previously saved cursor position
"""
restorecursor(io::IO=stdout) = write(io, "\e[u")

"""
Get cursor position
"""
cursor_position(io::IO=stdout) = write(io, "\e[6n")

# --------------------------------- movement --------------------------------- #

"""
Move cursor to the beginning of the previous line
"""
beginning_previous_line(io::IO=stdout) = write(io, "\e[F")

"""
Move cursor up one one or more lines
"""

prev_line(io::IO=stdout, n::Int=1) = write(io, "\e["*string(n)*"F")

up(io::IO=stdout, n::Int=1) = write(io, "\e["*string(n)*"A")

"""
Move cursor down one or more lines
"""
next_line(io::IO=stdout, n::Int=1) = write(io, "\e["*string(n)*"E")

down(io::IO=stdout, n::Int=1) = write(io, "\e["*string(n)*"B")

"""
Move cursor to a specific line
"""
move_to_line(io::IO=stdout, n::Int=1) = write(io, "\e["*string(n)*";1H")

# ---------------------------------- display --------------------------------- #
"""
Clear terminal.
"""
clear(io::IO=stdout) = write(io, "\e[2J")
cleartoend(io::IO=stdout) = write(io, "\e[0J")

"""
Hide cursor
"""
hide_cursor(io::IO=stdout) = write(io, "\e[?25l")

"""
Show cursor
"""
show_cursor(io::IO=stdout) = write(io, "\e[?25h")

"""
write a new line.
"""
line(io::IO=stdout, i=1) = write(io, "\n"^i)

"""
Erase last line in console.
"""
erase_line(io::IO=stdout) = write(io, "\e[2K")

"""
Change the position of the scrolling region in the terminal.

See: http://www.sweger.com/ansiplus/EscSeqScroll.html
"""
function change_scroll_region(io::IO=stdout, n::Int=1)
    write(io, "\e[1;" * string(n) * "r")  # from row 1 to n, all columns
    down(io, n)
end

# ---------------------------------------------------------------------------- #
#                                    CONSOLE                                   #
# ---------------------------------------------------------------------------- #
"""
    console_height()

Get the current console height.
"""
console_height(io::IO=stdout) = displaysize(io)[1]

"""
    console_width()

Get the current console width.
"""
console_width(io::IO=stdout) = displaysize(io)[2]

end


text:
__precompile__()

"""
    module QuantumBayesian

A Julia package for efficient simulation of quantum state evolution.
"""
module QuantumBayesian

#################################
# Package dependences and imports
#

# NOTE: there is no simple way to convert v0.5 to v0.7+ of julia
#       with the Compat module, since the syntax for inner
#       constructors has fundamentally changed. The present code
#       works only with v0.7+

using Interpolations
using SparseArrays
using Statistics
using LinearAlgebra
using SpecialFunctions
using Distributed

import Base.product

# Imported solely for method overloading purposes
import Base.show
import Base.length
import Base.size
import Base.getindex
import Base.setindex!
import Base.ndims
#import Base.indices
#import Base.print_matrix
import Base.map
import Statistics.mean
import Statistics.median
import Statistics.std
###

#################################
# Abstract types and type aliases
abstract type QObj <: Any end

# Note implementation is light-weight, using mostly type aliases
# for the features in Base that do all the real work
const Time = Float64
const QComp = ComplexF64
const QName = AbstractString
const QOp = AbstractArray
const QOpName = AbstractChar
const QOps = Dict{QOpName, QOp}
const QsOps = Dict{QName, QOp}
const QKet = AbstractVector
###

#######################
# Include functionality
include("Quantum.jl")
include("QuantumOscillator.jl")
include("QuantumBit.jl")
include("QuantumOperations.jl")
include("QuantumEvolution.jl")
###

#########
# Exports

# QuantumBayesian
export Time, QObj, QComp, QInd, QName, QOp, QOpName, QKet, QOps, QsOps
# Quantum
export QFactor, QSpace
export size, length, show, getindex, setindex!
export name, factors, subview
export superket, unsuperket, superopl, superopr
export ⊗, lift, ptr, bra
export osc, qubit
export groundvec, ground, projector, transition, coherentvec, coherent
export comm, acomm, ⊖, ⊕, sand, diss, inn
export scomm, sacomm, ssand, sdiss
export expect, expectvec, weakvalue, weakvaluevec
# QuantumEvolution
export Trajectory, Ensemble
export map, mean, median, std
export size, length, ndims
export ham, ham_rk4, lind, lind_rk4
export sham, slind
export meas, trajectory, ensemble, trajectoryToEnsemble
###

end # module


text:
# Autogenerated wrapper script for TtH_jll for x86_64-apple-darwin
export tth

JLLWrappers.@generate_wrapper_header("TtH")
JLLWrappers.@declare_executable_product(tth)
function __init__()
    JLLWrappers.@generate_init_header()
    JLLWrappers.@init_executable_product(
        tth,
        "bin/tth",
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
"""
PermTrack(args...)

Return Wyllie and Rose permeability correlation using either Timur or Morris coeficients as well as fluid type, oil or gas
``K=Cperm*\frac { { Phie }^{ Dperm } }{ { Sw }^{ Eperm } } ``

## coeficients
### Timur
Dperm=4.4
Eperm=2.0

For Oil
 Cperm=3400

For Gas
Cperm=340

### Morris
Dperm=6.0
Eperm=2.0

For Oil
 Cperm=65000

For Gas
Cperm=6500

## Example

```julia
k=PermWR(0.18,0.3;Fluid="Oil",Author="Timur")
```
"""

function PermWR(Phie,Swir;Fluid="Oil",Author="Timur")
    #https://www.spec2000.net/15-permwyllie.htm

    if (Author=="Timur")
        Dperm=4.4
        Eperm=2.0

        if (Fluid=="Oil")
         Cperm=3400
        elseif (Fluid=="Gas")
            Cperm=340
        end

    elseif (Author=="Morris")
        Dperm=6.0
        Eperm=2.0
           if (Fluid=="Oil")
         Cperm=65000
         elseif (Fluid=="Gas")
            Cperm=6500
        end

        end

    k=Cperm .* (Phie .^ Dperm) ./ (Swir .^ Eperm)
end