text:
#
# functions added by deps/dpi_patch.c
#

# int32_t odpi_version_number()
function odpi_version_number()
    ccall((:odpi_version_number, libdpi), Cint, ())
end

# size_t sizeof_dpiDataBuffer()
function sizeof_dpiDataBuffer()
    ccall((:sizeof_dpiDataBuffer, libdpi), Csize_t, ())
end

# size_t sizeof_dpiData()
function sizeof_dpiData()
    ccall((:sizeof_dpiData, libdpi), Csize_t, ())
end

# size_t sizeof_dpiTimestamp()
function sizeof_dpiTimestamp()
    ccall((:sizeof_dpiTimestamp, libdpi), Csize_t, ())
end

# size_t sizeof_dpiErrorInfo()
function sizeof_dpiErrorInfo()
    ccall((:sizeof_dpiErrorInfo, libdpi), Csize_t, ())
end

# size_t sizeof_dpiCommonCreateParams()
function sizeof_dpiCommonCreateParams()
    ccall((:sizeof_dpiCommonCreateParams, libdpi), Csize_t, ())
end

# size_t sizeof_dpiAppContext()
function sizeof_dpiAppContext()
    ccall((:sizeof_dpiAppContext, libdpi), Csize_t, ())
end

# size_t sizeof_dpiPoolCreateParams()
function sizeof_dpiPoolCreateParams()
    ccall((:sizeof_dpiPoolCreateParams, libdpi), Csize_t, ())
end

# size_t sizeof_dpiConnCreateParams()
function sizeof_dpiConnCreateParams()
    ccall((:sizeof_dpiConnCreateParams, libdpi), Csize_t, ())
end

# size_t sizeof_dpiDataTypeInfo()
function sizeof_dpiDataTypeInfo()
    ccall((:sizeof_dpiDataTypeInfo, libdpi), Csize_t, ())
end

# size_t sizeof_dpiQueryInfo()
function sizeof_dpiQueryInfo()
    ccall((:sizeof_dpiQueryInfo, libdpi), Csize_t, ())
end

# size_t sizeof_dpiStmtInfo()
function sizeof_dpiStmtInfo()
    ccall((:sizeof_dpiStmtInfo, libdpi), Csize_t, ())
end

# size_t sizeof_dpiVersionInfo()
function sizeof_dpiVersionInfo()
    ccall((:sizeof_dpiVersionInfo, libdpi), Csize_t, ())
end

# size_t sizeof_dpiBytes()
function sizeof_dpiBytes()
    ccall((:sizeof_dpiBytes, libdpi), Csize_t, ())
end

# size_t sizeof_dpiEncodingInfo()
function sizeof_dpiEncodingInfo()
    ccall((:sizeof_dpiEncodingInfo, libdpi), Csize_t, ())
end

# size_t sizeof_dpiObjectTypeInfo()
function sizeof_dpiObjectTypeInfo()
    ccall((:sizeof_dpiObjectTypeInfo, libdpi), Csize_t, ())
end

# see issue #21
# size_t sizeof_dpiNumber()
#function sizeof_dpiNumber()
#    ccall((:sizeof_dpiNumber, libdpi), Csize_t, ())
#end

#
# ODPI Context Functions
#

# int dpiContext_createWithParams(unsigned int majorVersion, unsigned int minorVersion, dpiContextCreateParams *params, dpiContext **context, dpiErrorInfo *errorInfo)
function dpiContext_createWithParams(major_version::UInt32, minor_version::UInt32, dpi_context_ref::Ref{Ptr{Cvoid}}, error_info::Ref{OraErrorInfo})
    ccall((:dpiContext_createWithParams, libdpi), OraResult, (Cuint, Cuint, Ptr{Cvoid}, Ref{Ptr{Cvoid}}, Ref{OraErrorInfo}), major_version, minor_version, C_NULL, dpi_context_ref, error_info)
end

# int dpiContext_destroy(dpiContext *context)
function dpiContext_destroy(dpi_context_handle::Ptr{Cvoid})
    ccall((:dpiContext_destroy, libdpi), OraResult, (Ptr{Cvoid},), dpi_context_handle)
end

# int dpiContext_getClientVersion(const dpiContext *context, dpiVersionInfo *versionInfo)
function dpiContext_getClientVersion(dpi_context_handle::Ptr{Cvoid}, version_info_ref::Ref{OraVersionInfo})
    ccall((:dpiContext_getClientVersion, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraVersionInfo}), dpi_context_handle, version_info_ref)
end

# int dpiContext_initCommonCreateParams(const dpiContext *context, dpiContextParams *params)
function dpiContext_initCommonCreateParams(dpi_context_handle::Ptr{Cvoid}, common_create_params_ref::Ref{OraCommonCreateParams})
    ccall((:dpiContext_initCommonCreateParams, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraCommonCreateParams}), dpi_context_handle, common_create_params_ref)
end

# int dpiContext_initPoolCreateParams(const dpiContext *context, dpiPoolCreateParams *params)
function dpiContext_initPoolCreateParams(context_handle::Ptr{Cvoid}, pool_create_params_ref::Ref{OraPoolCreateParams})
    ccall((:dpiContext_initPoolCreateParams, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraPoolCreateParams}), context_handle, pool_create_params_ref)
end

# void dpiContext_getError(const dpiContext *context, dpiErrorInfo *errorInfo)¶
function dpiContext_getError(context_handle::Ptr{Cvoid}, error_info_ref::Ref{OraErrorInfo})
    ccall((:dpiContext_getError, libdpi), Cvoid, (Ptr{Cvoid}, Ref{OraErrorInfo}), context_handle, error_info_ref)
end

# int dpiContext_initConnCreateParams(const dpiContext *context, dpiConnCreateParams *params)
function dpiContext_initConnCreateParams(context_handle::Ptr{Cvoid}, conn_create_params_ref::Ref{OraConnCreateParams})
    ccall((:dpiContext_initConnCreateParams, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraConnCreateParams}), context_handle, conn_create_params_ref)
end

#
# ODPI Connection Functions
#

# int dpiConn_release(dpiConn *conn)
function dpiConn_release(connection_handle::Ptr{Cvoid})
    ccall((:dpiConn_release, libdpi), OraResult, (Ptr{Cvoid},), connection_handle)
end

# int dpiConn_create(const dpiContext *context, const char *userName, uint32_t userNameLength, const char *password, uint32_t passwordLength, const char *connectString, uint32_t connectStringLength, dpiCommonCreateParams *commonParams, dpiConnCreateParams *createParams, dpiConn **conn)
function dpiConn_create(context_handle::Ptr{Cvoid}, user::String, password::String, connect_string::String, common_params_ref::Ref{OraCommonCreateParams}, conn_create_params_ref::Ref{OraConnCreateParams}, dpi_conn_handle_ref::Ref{Ptr{Cvoid}})
    userNameLength = sizeof(user)
    passwordLength = sizeof(password)
    connectStringLength = sizeof(connect_string)

    ccall((:dpiConn_create, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ref{OraCommonCreateParams}, Ref{OraConnCreateParams}, Ref{Ptr{Cvoid}}), context_handle, user, userNameLength, password, passwordLength, connect_string, connectStringLength, common_params_ref, conn_create_params_ref, dpi_conn_handle_ref)
end

# int dpiConn_getServerVersion(dpiConn *conn, const char **releaseString, uint32_t *releaseStringLength, dpiVersionInfo *versionInfo)
function dpiConn_getServerVersion(connection_handle::Ptr{Cvoid}, release_string_ptr_ref::Ref{Ptr{UInt8}}, release_string_length_ref::Ref{UInt32}, version_info_ref::Ref{OraVersionInfo})
    ccall((:dpiConn_getServerVersion, libdpi), OraResult, (Ptr{Cvoid}, Ref{Ptr{UInt8}}, Ref{UInt32}, Ref{OraVersionInfo}), connection_handle, release_string_ptr_ref, release_string_length_ref, version_info_ref)
end

#int dpiConn_ping(dpiConn *conn)
function dpiConn_ping(connection_handle::Ptr{Cvoid})
    ccall((:dpiConn_ping, libdpi), OraResult, (Ptr{Cvoid},), connection_handle)
end

# int dpiConn_startupDatabase(dpiConn *conn, dpiStartupMode mode)
function dpiConn_startupDatabase(connection_handle::Ptr{Cvoid}, startup_mode::OraStartupMode)
    ccall((:dpiConn_startupDatabase, libdpi), OraResult, (Ptr{Cvoid}, OraStartupMode), connection_handle, startup_mode)
end

# int dpiConn_shutdownDatabase(dpiConn *conn, dpiShutdownMode mode)
function dpiConn_shutdownDatabase(connection_handle::Ptr{Cvoid}, shutdown_mode::OraShutdownMode)
    ccall((:dpiConn_shutdownDatabase, libdpi), OraResult, (Ptr{Cvoid}, OraShutdownMode), connection_handle, shutdown_mode)
end

# int dpiConn_prepareStmt(dpiConn *conn, int scrollable, const char *sql, uint32_t sqlLength, const char *tag, uint32_t tagLength, dpiStmt **stmt)
function dpiConn_prepareStmt(connection_handle::Ptr{Cvoid}, scrollable::Bool, sql::String, tag::String, stmt_handle_ref::Ref{Ptr{Cvoid}})
    sqlLength = sizeof(sql)

    if tag == ""
        return ccall((:dpiConn_prepareStmt, libdpi), OraResult, (Ptr{Cvoid}, Cint, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ref{Ptr{Cvoid}}), connection_handle, scrollable, sql, sqlLength, C_NULL, 0, stmt_handle_ref)
    else
        tagLength = sizeof(tag)
        return ccall((:dpiConn_prepareStmt, libdpi), OraResult, (Ptr{Cvoid}, Cint, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ref{Ptr{Cvoid}}), connection_handle, scrollable, sql, sqlLength, tag, tagLength, stmt_handle_ref)
    end
end

# int dpiConn_close(dpiConn *conn, dpiConnCloseMode mode, const char *tag, uint32_t tagLength)
function dpiConn_close(connection_handle::Ptr{Cvoid}; close_mode::OraConnCloseMode=ORA_MODE_CONN_CLOSE_DEFAULT, tag::String="")
    if tag == ""
        return ccall((:dpiConn_close, libdpi), OraResult, (Ptr{Cvoid}, OraConnCloseMode, Ptr{UInt8}, UInt32), connection_handle, close_mode, C_NULL, 0)
    else
        tagLength = sizeof(tag)
        return ccall((:dpiConn_close, libdpi), OraResult, (Ptr{Cvoid}, OraConnCloseMode, Ptr{UInt8}, UInt32), connection_handle, close_mode, tag, tagLength)
    end
end

# int dpiConn_commit(dpiConn *conn)
function dpiConn_commit(connection_handle::Ptr{Cvoid})
    ccall((:dpiConn_commit, libdpi), OraResult, (Ptr{Cvoid},), connection_handle)
end

# int dpiConn_rollback(dpiConn *conn)
function dpiConn_rollback(connection_handle::Ptr{Cvoid})
    ccall((:dpiConn_rollback, libdpi), OraResult, (Ptr{Cvoid},), connection_handle)
end

# int dpiConn_getEncodingInfo(dpiConn *conn, dpiEncodingInfo *info)
function dpiConn_getEncodingInfo(connection_handle::Ptr{Cvoid}, encoding_info_ref::Ref{OraEncodingInfo})
    ccall((:dpiConn_getEncodingInfo, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraEncodingInfo}), connection_handle, encoding_info_ref)
end

# int dpiConn_getCurrentSchema(dpiConn *conn, const char **value, uint32_t *valueLength)
function dpiConn_getCurrentSchema(connection_handle::Ptr{Cvoid}, value_char_array_ref::Ref{Ptr{UInt8}}, value_length_ref::Ref{UInt32})
    ccall((:dpiConn_getCurrentSchema, libdpi), OraResult, (Ptr{Cvoid}, Ref{Ptr{UInt8}}, Ref{UInt32}), connection_handle, value_char_array_ref, value_length_ref)
end

# int dpiConn_newVar(dpiConn *conn, dpiOracleTypeNum oracleTypeNum, dpiNativeTypeNum nativeTypeNum, uint32_t maxArraySize, uint32_t size, int sizeIsBytes, int isArray, dpiObjectType *objType, dpiVar **var, dpiData **data)
function dpiConn_newVar(connection_handle::Ptr{Cvoid}, oracle_type::OraOracleTypeNum, native_type::OraNativeTypeNum, max_array_size::UInt32, size::UInt32, size_is_bytes::Int32, is_array::Int32, obj_type_handle::Ptr{Cvoid}, var_handle_ref::Ref{Ptr{Cvoid}}, dpi_data_array_ref::Ref{Ptr{OraData}})
    ccall((:dpiConn_newVar, libdpi), OraResult, (Ptr{Cvoid}, OraOracleTypeNum, OraNativeTypeNum, UInt32, UInt32, Int32, Int32, Ptr{Cvoid}, Ref{Ptr{Cvoid}}, Ref{Ptr{OraData}}), connection_handle, oracle_type, native_type, max_array_size, size, size_is_bytes, is_array, obj_type_handle, var_handle_ref, dpi_data_array_ref)
end

# int dpiConn_getStmtCacheSize(dpiConn *conn, uint32_t *cacheSize)
function dpiConn_getStmtCacheSize(connection_handle::Ptr{Cvoid}, cache_size_ref::Ref{UInt32})
    ccall((:dpiConn_getStmtCacheSize, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), connection_handle, cache_size_ref)
end

# int dpiConn_setStmtCacheSize(dpiConn *conn, uint32_t cacheSize)
function dpiConn_setStmtCacheSize(connection_handle::Ptr{Cvoid}, cache_size::UInt32)
    ccall((:dpiConn_setStmtCacheSize, libdpi), OraResult, (Ptr{Cvoid}, UInt32), connection_handle, cache_size)
end

# int dpiConn_newTempLob(dpiConn *conn, dpiOracleTypeNum lobType, dpiLob **lob)
function dpiConn_newTempLob(connection_handle::Ptr{Cvoid}, lob_type::OraOracleTypeNum, lob_handle_ref::Ref{Ptr{Cvoid}})
    ccall((:dpiConn_newTempLob, libdpi), OraResult, (Ptr{Cvoid}, OraOracleTypeNum, Ref{Ptr{Cvoid}}), connection_handle, lob_type, lob_handle_ref)
end

# int dpiConn_setClientIdentifier(dpiConn *conn, const char *value, uint32_t valueLength)
function dpiConn_setClientIdentifier(connection_handle::Ptr{Cvoid}, value::String)
    value_length = sizeof(value)
    ccall((:dpiConn_setClientIdentifier, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32), connection_handle, value, value_length)
end

# int dpiConn_setClientInfo(dpiConn *conn, const char *value, uint32_t valueLength)
function dpiConn_setClientInfo(connection_handle::Ptr{Cvoid}, value::String)
    value_length = sizeof(value)
    ccall((:dpiConn_setClientInfo, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32), connection_handle, value, value_length)
end

#
# ODPI Pool Functions
#

# int dpiPool_create(const dpiContext *context, const char *userName, uint32_t userNameLength, const char *password, uint32_t passwordLength, const char *connectString, uint32_t connectStringLength, dpiCommonCreateParams *commonParams, dpiPoolCreateParams *createParams, dpiPool **pool)
function dpiPool_create(context_handle::Ptr{Cvoid}, user::String, password::String, connect_string::String, common_params_ref::Ref{OraCommonCreateParams}, pool_create_params_ref::Ref{OraPoolCreateParams}, pool_handle_ref::Ref{Ptr{Cvoid}})
    userNameLength = sizeof(user)
    passwordLength = sizeof(password)
    connectStringLength = sizeof(connect_string)

    ccall((:dpiPool_create, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ref{OraCommonCreateParams}, Ref{OraPoolCreateParams}, Ref{Ptr{Cvoid}}), context_handle, user, userNameLength, password, passwordLength, connect_string, connectStringLength, common_params_ref, pool_create_params_ref, pool_handle_ref)
end

# int dpiPool_release(dpiPool *pool)
function dpiPool_release(dpi_pool_handle::Ptr{Cvoid})
    ccall((:dpiPool_release, libdpi), OraResult, (Ptr{Cvoid},), dpi_pool_handle)
end

# int dpiPool_close(dpiPool *pool, dpiPoolCloseMode closeMode)
function dpiPool_close(pool_handle::Ptr{Cvoid}, close_mode::OraPoolCloseMode)
    ccall((:dpiPool_close, libdpi), OraResult, (Ptr{Cvoid}, OraPoolCloseMode), pool_handle, close_mode)
end

# int dpiPool_getGetMode(dpiPool *pool, dpiPoolGetMode *value)
function dpiPool_getGetMode(pool_handle::Ptr{Cvoid}, pool_get_mode_ref::Ref{OraPoolGetMode})
    ccall((:dpiPool_getGetMode, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraPoolGetMode}), pool_handle, pool_get_mode_ref)
end

# int dpiPool_acquireConnection(dpiPool *pool, const char *userName, uint32_t userNameLength, const char *password, uint32_t passwordLength, dpiConnCreateParams *params, dpiConn **conn)
function dpiPool_acquireConnection(pool_handle::Ptr{Cvoid}, user::String, password::String, conn_create_params_ref::Ref{OraConnCreateParams}, connection_handle_ref::Ref{Ptr{Cvoid}})
    userNameLength = sizeof(user)
    passwordLength = sizeof(password)
    ccall((:dpiPool_acquireConnection, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ref{OraConnCreateParams}, Ref{Ptr{Cvoid}}), pool_handle, user, userNameLength, password, passwordLength, conn_create_params_ref, connection_handle_ref)
end

function dpiPool_acquireConnection(pool_handle::Ptr{Cvoid}, conn_create_params_ref::Ref{OraConnCreateParams}, connection_handle_ref::Ref{Ptr{Cvoid}})
    ccall((:dpiPool_acquireConnection, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ptr{UInt8}, UInt32, Ref{OraConnCreateParams}, Ref{Ptr{Cvoid}}), pool_handle, C_NULL, 0, C_NULL, 0, conn_create_params_ref, connection_handle_ref)
end

function dpiPool_getOpenCount(pool_handle::Ptr{Cvoid}, value::Ref{UInt32})
    ccall((:dpiPool_getOpenCount, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), pool_handle, value)
end

function dpiPool_getBusyCount(pool_handle::Ptr{Cvoid}, value::Ref{UInt32})
    ccall((:dpiPool_getBusyCount, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), pool_handle, value)
end

#
# ODPI Statement Functions
#

# int dpiStmt_release(dpiStmt *stmt)
function dpiStmt_release(stmt_handle::Ptr{Cvoid})
    ccall((:dpiStmt_release, libdpi), OraResult, (Ptr{Cvoid},), stmt_handle)
end

# int dpiStmt_close(dpiStmt *stmt, const char *tag, uint32_t tagLength)
function dpiStmt_close(stmt_handle::Ptr{Cvoid}; tag::String="")
    if tag == ""
        return ccall((:dpiStmt_close, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32), stmt_handle, C_NULL, 0)
    else
        tagLength = sizeof(tag)
        return ccall((:dpiStmt_close, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32), stmt_handle, tag, tagLength)
    end
end

# int dpiStmt_execute(dpiStmt *stmt, dpiExecMode mode, uint32_t *numQueryColumns)
function dpiStmt_execute(stmt_handle::Ptr{Cvoid}, exec_mode::OraExecMode, num_query_columns_ref::Ref{UInt32})
    ccall((:dpiStmt_execute, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ref{UInt32}), stmt_handle, exec_mode, num_query_columns_ref)
end

# int dpiStmt_executeMany(dpiStmt *stmt, dpiExecMode mode, uint32_t numIters)
function dpiStmt_executeMany(stmt_handle::Ptr{Cvoid}, exec_mode::OraExecMode, num_iters::UInt32)
    ccall((:dpiStmt_executeMany, libdpi), OraResult, (Ptr{Cvoid}, UInt32, UInt32), stmt_handle, exec_mode, num_iters)
end

# int dpiStmt_getRowCounts(dpiStmt *stmt, uint32_t *numRowCounts, uint64_t **rowCounts)
function dpiStmt_getRowCounts(stmt_handle::Ptr{Cvoid}, row_counts_length_ref::Ref{UInt32}, row_counts_array_ref::Ref{Ptr{UInt64}})
    ccall((:dpiStmt_getRowCounts, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}, Ref{Ptr{UInt64}}), stmt_handle, row_counts_length_ref, row_counts_array_ref)
end

# int dpiStmt_getNumQueryColumns(dpiStmt *stmt, uint32_t *numQueryColumns)
function dpiStmt_getNumQueryColumns(stmt_handle::Ptr{Cvoid}, num_query_columns_ref::Ref{UInt32})
    ccall((:dpiStmt_getNumQueryColumns, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), stmt_handle, num_query_columns_ref)
end

# int dpiStmt_getQueryInfo(dpiStmt *stmt, uint32_t pos, dpiQueryInfo *info)
function dpiStmt_getQueryInfo(stmt_handle::Ptr{Cvoid}, pos::UInt32, query_info_ref::Ref{OraQueryInfo})
    ccall((:dpiStmt_getQueryInfo, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ref{OraQueryInfo}), stmt_handle, pos, query_info_ref)
end

# int dpiStmt_getInfo(dpiStmt *stmt, dpiStmtInfo *info)
function dpiStmt_getInfo(stmt_handle::Ptr{Cvoid}, stmt_info_ref::Ref{OraStmtInfo})
    ccall((:dpiStmt_getInfo, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraStmtInfo}), stmt_handle, stmt_info_ref)
end

# int dpiStmt_getFetchArraySize(dpiStmt *stmt, uint32_t *arraySize)
function dpiStmt_getFetchArraySize(stmt_handle::Ptr{Cvoid}, array_size_ref::Ref{UInt32})
    ccall((:dpiStmt_getFetchArraySize, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), stmt_handle, array_size_ref)
end

# int dpiStmt_setFetchArraySize(dpiStmt *stmt, uint32_t arraySize)
function dpiStmt_setFetchArraySize(stmt_handle::Ptr{Cvoid}, array_size::UInt32)
    ccall((:dpiStmt_setFetchArraySize, libdpi), OraResult, (Ptr{Cvoid}, UInt32), stmt_handle, array_size)
end

# int dpiStmt_fetch(dpiStmt *stmt, int *found, uint32_t *bufferRowIndex)
function dpiStmt_fetch(stmt_handle::Ptr{Cvoid}, found_ref::Ref{Int32}, buffer_row_index_ref::Ref{UInt32})
    ccall((:dpiStmt_fetch, libdpi), OraResult, (Ptr{Cvoid}, Ref{Int32}, Ref{UInt32}), stmt_handle, found_ref, buffer_row_index_ref)
end

# int dpiStmt_fetchRows(dpiStmt *stmt, uint32_t maxRows, uint32_t *bufferRowIndex, uint32_t *numRowsFetched, int *moreRows)
function dpiStmt_fetchRows(stmt_handle::Ptr{Cvoid}, max_rows::UInt32, buffer_row_index_ref::Ref{UInt32}, num_rows_fetched_ref::Ref{UInt32}, more_rows_ref::Ref{Int32})
    ccall((:dpiStmt_fetchRows, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ref{UInt32}, Ref{UInt32}, Ref{Int32}), stmt_handle, max_rows, buffer_row_index_ref, num_rows_fetched_ref, more_rows_ref)
end

# int dpiStmt_getQueryValue(dpiStmt *stmt, uint32_t pos, dpiNativeTypeNum *nativeTypeNum, dpiData **data)
function dpiStmt_getQueryValue(stmt_handle::Ptr{Cvoid}, pos::UInt32, native_type_num_ref::Ref{OraNativeTypeNum}, data_handle_ref::Ref{Ptr{OraData}})
    ccall((:dpiStmt_getQueryValue, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ref{OraNativeTypeNum}, Ref{Ptr{OraData}}), stmt_handle, pos, native_type_num_ref, data_handle_ref)
end

# int dpiStmt_bindValueByName(dpiStmt *stmt, const char *name, uint32_t nameLength, dpiNativeTypeNum nativeTypeNum, dpiData *data)
function dpiStmt_bindValueByName(stmt_handle::Ptr{Cvoid}, name::String, native_type::OraNativeTypeNum, dpi_data_ref::Ref{OraData})
    nameLength = sizeof(name)
    ccall((:dpiStmt_bindValueByName, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, OraNativeTypeNum, Ref{OraData}), stmt_handle, name, nameLength, native_type, dpi_data_ref)
end

# int dpiStmt_bindValueByPos(dpiStmt *stmt, uint32_t pos, dpiNativeTypeNum nativeTypeNum, dpiData *data)
function dpiStmt_bindValueByPos(stmt_handle::Ptr{Cvoid}, pos::UInt32, native_type::OraNativeTypeNum, dpi_data_ref::Ref{OraData})
    ccall((:dpiStmt_bindValueByPos, libdpi), OraResult, (Ptr{Cvoid}, UInt32, OraNativeTypeNum, Ref{OraData}), stmt_handle, pos, native_type, dpi_data_ref)
end

# int dpiStmt_getRowCount(dpiStmt *stmt, uint64_t *count)
function dpiStmt_getRowCount(stmt_handle::Ptr{Cvoid}, count_ref::Ref{UInt64})
    ccall((:dpiStmt_getRowCount, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt64}), stmt_handle, count_ref)
end

# int dpiStmt_getBindCount(dpiStmt *stmt, uint32_t *count)
function dpiStmt_getBindCount(stmt_handle::Ptr{Cvoid}, count_ref::Ref{UInt32})
    ccall((:dpiStmt_getBindCount, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), stmt_handle, count_ref)
end

# int dpiStmt_getBindNames(dpiStmt *stmt, uint32_t *numBindNames, const char **bindNames, uint32_t *bindNameLengths)
function dpiStmt_getBindNames(stmt_handle::Ptr{Cvoid}, num_bind_names_ref::Ref{UInt32}, bind_names_vec_ptr::Ptr{Ptr{UInt8}}, bind_name_lengths_vector::Ptr{UInt32})
    ccall((:dpiStmt_getBindNames, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}, Ref{Ptr{UInt8}}, Ptr{UInt32}), stmt_handle, num_bind_names_ref, bind_names_vec_ptr, bind_name_lengths_vector)
end

# int dpiStmt_define(dpiStmt *stmt, uint32_t pos, dpiVar *var)
function dpiStmt_define(stmt_handle::Ptr{Cvoid}, pos::UInt32, variable_handle::Ptr{Cvoid})
    ccall((:dpiStmt_define, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ptr{Cvoid}), stmt_handle, pos, variable_handle)
end

# int dpiStmt_bindByName(dpiStmt *stmt, const char *name, uint32_t nameLength, dpiVar *var)
function dpiStmt_bindByName(stmt_handle::Ptr{Cvoid}, name::String, variable_handle::Ptr{Cvoid})
    nameLength = sizeof(name)
    ccall((:dpiStmt_bindByName, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ptr{Cvoid}), stmt_handle, name, nameLength, variable_handle)
end

# int dpiStmt_bindByPos(dpiStmt *stmt, uint32_t pos, dpiVar *var)
function dpiStmt_bindByPos(stmt_handle::Ptr{Cvoid}, pos::UInt32, variable_handle::Ptr{Cvoid})
    ccall((:dpiStmt_bindByPos, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ptr{Cvoid}), stmt_handle, pos, variable_handle)
end

#
# ODPI Data Functions
#

# int dpiData_getBool(dpiData *data)
function dpiData_getBool(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getBool, libdpi), Cint, (Ref{OraData},), dpi_data_handle)
end

# double dpiData_getDouble(dpiData *data)
function dpiData_getDouble(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getDouble, libdpi), Cdouble, (Ref{OraData},), dpi_data_handle)
end

# float dpiData_getFloat(dpiData *data)
function dpiData_getFloat(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getFloat, libdpi), Float32, (Ref{OraData},), dpi_data_handle)
end

# int64_t dpiData_getInt64(dpiData *data)
function dpiData_getInt64(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getInt64, libdpi), Int64, (Ref{OraData},), dpi_data_handle)
end

# uint64_t dpiData_getUint64(dpiData *data)
function dpiData_getUint64(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getUint64, libdpi), UInt64, (Ref{OraData},), dpi_data_handle)
end

# dpiBytes *dpiData_getBytes(dpiData *data)
function dpiData_getBytes(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getBytes, libdpi), Ptr{OraBytes}, (Ref{OraData},), dpi_data_handle)
end

# dpiTimestamp *dpiData_getTimestamp(dpiData *data)
function dpiData_getTimestamp(dpi_data_handle::Ref{OraData})
    ccall((:dpiData_getTimestamp, libdpi), Ptr{OraTimestamp}, (Ref{OraData},), dpi_data_handle)
end

# int dpiData_getIsNull(dpiData *data)
function dpiData_getIsNull(data_handle::Ref{OraData})
    ccall((:dpiData_getIsNull, libdpi), Cint, (Ref{OraData},), data_handle)
end

# dpiLob *dpiData_getLOB(dpiData *data)
function dpiData_getLOB(data_handle::Ref{OraData})
    ccall((:dpiData_getLOB, libdpi), Ptr{Cvoid}, (Ref{OraData},), data_handle)
end

# see issue #21
## dpiNumber dpiData_getNumber(dpiData *data);
#function dpiData_getNumber(data_handle::Ref{OraData})
#    ccall((:dpiData_getNumber, libdpi), OraNumber, (Ref{OraData},), data_handle)
#end

#
# NOTE ON SET FUNCTIONS
#
# Ref{OraData} <: Ptr{OraData}
#

# void dpiData_setBytes(dpiData *data, char *ptr, uint32_t length)
# cannot be used for setting strings to variables
function dpiData_setBytes(dpi_data_ptr::Ref{OraData}, str::String)
    ccall((:dpiData_setBytes, libdpi), Cvoid, (Ref{OraData}, Ptr{UInt8}, UInt32), dpi_data_ptr, str, sizeof(str))
end

function dpiData_setBytes(dpi_data_ptr::Ref{OraData}, bytes::Vector{UInt8})
    ccall((:dpiData_setBytes, libdpi), Cvoid, (Ref{OraData}, Ptr{UInt8}, UInt32), dpi_data_ptr, bytes, length(bytes))
end

function dpiData_setBytes(dpi_data_ptr::Ref{OraData}, bytes_ptr::Ptr{UInt8}, bytes_len::UInt32)
    ccall((:dpiData_setBytes, libdpi), Cvoid, (Ref{OraData}, Ptr{UInt8}, UInt32), dpi_data_ptr, bytes_ptr, bytes_len)
end

# void dpiData_setDouble(dpiData *data, double value)
function dpiData_setDouble(dpi_data_ptr::Ref{OraData}, value::Float64)
    ccall((:dpiData_setDouble, libdpi), Cvoid, (Ref{OraData}, Cdouble), dpi_data_ptr, value)
end

# void dpiData_setInt64(dpiData *data, int64_t value)
function dpiData_setInt64(dpi_data_ptr::Ref{OraData}, value::Int64)
    ccall((:dpiData_setInt64, libdpi), Cvoid, (Ref{OraData}, Int64), dpi_data_ptr, value)
end

# void dpiData_setUint64(dpiData *data, uint64_t value)
function dpiData_setUint64(dpi_data_ptr::Ref{OraData}, value::UInt64)
    ccall((:dpiData_setUint64, libdpi), Cvoid, (Ref{OraData}, UInt64), dpi_data_ptr, value)
end

# void dpiData_setTimestamp(dpiData *data, int16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t fsecond, int8_t tzHourOffset, int8_t tzMinuteOffset)
function dpiData_setTimestamp(dpi_data_ptr::Ref{OraData}, ts::OraTimestamp)
    ccall((:dpiData_setTimestamp, libdpi), Cvoid, (Ref{OraData}, Int16, UInt8, UInt8, UInt8, UInt8, UInt8, UInt32, Int8, Int8), dpi_data_ptr, ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fsecond, ts.tzHourOffset, ts.tzMinuteOffset)
end

# void dpiData_setNull(dpiData *data)
function dpiData_setNull(dpi_data_ptr::Ref{OraData})
    ccall((:dpiData_setNull, libdpi), Cvoid, (Ref{OraData},), dpi_data_ptr)
end

# void dpiData_setLOB(dpiData *data, dpiLob *lob)
function dpiData_setLOB(dpi_data_ptr::Ref{OraData}, lob_handle::Ptr{Cvoid})
    ccall((:dpiData_setLOB, libdpi), Cvoid, (Ref{OraData}, Ptr{Cvoid}), dpi_data_ptr, lob_handle)
end

# see issue #21
## void dpiData_setNumber(dpiData *data, dpiNumber number);
#function dpiData_setNumber(dpi_data_ptr::Ref{OraData}, number::OraNumber)
#    ccall((:dpiData_setNumber, libdpi), Cvoid, (Ref{OraData}, OraNumber), dpi_data_ptr, number)
#end

# void dpiData_setBool(dpiData *data, int value)
function dpiData_setBool(dpi_data_ptr::Ref{OraData}, val::Union{Bool, Integer})
    ccall((:dpiData_setBool, libdpi), Cvoid, (Ref{OraData}, Cint), dpi_data_ptr, val)
end

#
# ODPI-C Variable Functions
#

# int dpiVar_release(dpiVar *var)
function dpiVar_release(var_handle::Ptr{Cvoid})
    ccall((:dpiVar_release, libdpi), OraResult, (Ptr{Cvoid},), var_handle)
end

# int dpiVar_setFromBytes(dpiVar *var, uint32_t pos, const char *value, uint32_t valueLength)
function dpiVar_setFromBytes(var_handle::Ptr{Cvoid}, pos::UInt32, value::String)
    valueLength = sizeof(value)
    ccall((:dpiVar_setFromBytes, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ptr{UInt8}, UInt32), var_handle, pos, value, valueLength)
end

function dpiVar_setFromBytes(var_handle::Ptr{Cvoid}, pos::UInt32, value::Vector{UInt8})
    ccall((:dpiVar_setFromBytes, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ptr{UInt8}, UInt32), var_handle, pos, value, length(value))
end

# int dpiVar_setFromLob(dpiVar *var, uint32_t pos, dpiLob *lob)
function dpiVar_setFromLob(var_handle::Ptr{Cvoid}, pos::UInt32, lob_handle::Ptr{Cvoid})
    ccall((:dpiVar_setFromLob, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ptr{Cvoid}), var_handle, pos, lob_handle)
end

# int dpiVar_getNumElementsInArray(dpiVar *var, uint32_t *numElements)
function dpiVar_getNumElementsInArray(var_handle::Ptr{Cvoid}, ref_num_elements::Ref{UInt32})
    ccall((:dpiVar_getNumElementsInArray, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), var_handle, ref_num_elements)
end

# int dpiVar_getReturnedData(dpiVar *var, uint32_t pos, uint32_t *numElements, dpiData **data)
function dpiVar_getReturnedData(var_handle::Ptr{Cvoid}, pos::UInt32, ref_num_elements::Ref{UInt32}, ref_data_array::Ref{Ptr{OraData}})
    ccall((:dpiVar_getReturnedData, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ref{UInt32}, Ref{Ptr{OraData}}), var_handle, pos, ref_num_elements, ref_data_array)
end

#
# ODPI-C LOB Functions
#

# int dpiLob_release(dpiLob *lob)
function dpiLob_release(lob_handle::Ptr{Cvoid})
    ccall((:dpiLob_release, libdpi), OraResult, (Ptr{Cvoid},), lob_handle)
end

# int dpiLob_addRef(dpiLob *lob)
function dpiLob_addRef(lob_handle::Ptr{Cvoid})
    ccall((:dpiLob_addRef, libdpi), OraResult, (Ptr{Cvoid},), lob_handle)
end

# int dpiLob_close(dpiLob *lob)
function dpiLob_close(lob_handle::Ptr{Cvoid})
    ccall((:dpiLob_close, libdpi), OraResult, (Ptr{Cvoid},), lob_handle)
end

# int dpiLob_getChunkSize(dpiLob *lob, uint32_t *size)
function dpiLob_getChunkSize(lob_handle::Ptr{Cvoid}, chunk_size_ref::Ref{UInt32})
    ccall((:dpiLob_getChunkSize, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}), lob_handle, chunk_size_ref)
end

# int dpiLob_getSize(dpiLob *lob, uint64_t *size)
function dpiLob_getSize(lob_handle::Ptr{Cvoid}, lob_size_ref::Ref{UInt64})
    ccall((:dpiLob_getSize, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt64}), lob_handle, lob_size_ref)
end

# int dpiLob_readBytes(dpiLob *lob, uint64_t offset, uint64_t amount, char *value, uint64_t *valueLength)
function dpiLob_readBytes(lob_handle::Ptr{Cvoid}, offset::UInt64, amount::UInt64, buffer::Ptr{UInt8}, buffer_len_ref::Ref{UInt64})
    ccall((:dpiLob_readBytes, libdpi), OraResult, (Ptr{Cvoid}, UInt64, UInt64, Ptr{UInt8}, Ref{UInt64}), lob_handle, offset, amount, buffer, buffer_len_ref)
end

# int dpiLob_writeBytes(dpiLob *lob, uint64_t offset, const char *value, uint64_t valueLength)
function dpiLob_writeBytes(lob_handle::Ptr{Cvoid}, offset::UInt64, buffer::Ptr{UInt8}, buffer_len::UInt64)
    ccall((:dpiLob_writeBytes, libdpi), OraResult, (Ptr{Cvoid}, UInt64, Ptr{UInt8}, UInt64), lob_handle, offset, buffer, buffer_len)
end

# int dpiLob_openResource(dpiLob *lob)
function dpiLob_openResource(lob_handle::Ptr{Cvoid})
    ccall((:dpiLob_openResource, libdpi), OraResult, (Ptr{Cvoid},), lob_handle)
end

# int dpiLob_closeResource(dpiLob *lob)
function dpiLob_closeResource(lob_handle::Ptr{Cvoid})
    ccall((:dpiLob_closeResource, libdpi), OraResult, (Ptr{Cvoid},), lob_handle)
end

# int dpiLob_getIsResourceOpen(dpiLob *lob, int *isOpen)
function dpiLob_getIsResourceOpen(lob_handle::Ptr{Cvoid}, is_open_ref::Ref{Int32})
    ccall((:dpiLob_getIsResourceOpen, libdpi), OraResult, (Ptr{Cvoid}, Ref{Int32}), lob_handle, is_open_ref)
end

# int dpiLob_getBufferSize(dpiLob *lob, uint64_t sizeInChars, uint64_t *sizeInBytes)
function dpiLob_getBufferSize(lob_handle::Ptr{Cvoid}, size_in_chars::UInt64, size_in_bytes_ref::Ref{UInt64})
    ccall((:dpiLob_getBufferSize, libdpi), OraResult, (Ptr{Cvoid}, UInt64, Ref{UInt64}), lob_handle, size_in_chars, size_in_bytes_ref)
end

# int dpiLob_trim(dpiLob *lob, uint64_t newSize)
function dpiLob_trim(lob_handle::Ptr{Cvoid}, new_size::UInt64)
    ccall((:dpiLob_trim, libdpi), OraResult, (Ptr{Cvoid}, UInt64), lob_handle, new_size)
end

# int dpiLob_setFromBytes(dpiLob *lob, const char *value, uint64_t valueLength)
function dpiLob_setFromBytes(lob_handle::Ptr{Cvoid}, buffer::Ptr{UInt8}, buffer_len::UInt64)
    ccall((:dpiLob_setFromBytes, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt64), lob_handle, buffer, buffer_len)
end

#
# ODPI-C Object Functions
#

# int dpiObjectType_release(dpiObjectType *objType)
function dpiObjectType_release(obj_type_handle::Ptr{Cvoid})
    ccall((:dpiObjectType_release, libdpi), OraResult, (Ptr{Cvoid},), obj_type_handle)
end

# int dpiConn_getObjectType(dpiConn *conn, const char *name, uint32_t nameLength, dpiObjectType **objType)
function dpiConn_getObjectType(conn_handle::Ptr{Cvoid}, name::AbstractString, obj_type_handle_ref::Ref{Ptr{Cvoid}})
    ccall((:dpiConn_getObjectType, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ref{Ptr{Cvoid}}), conn_handle, name, sizeof(name), obj_type_handle_ref)
end

# int dpiObjectType_getInfo(dpiObjectType *objType, dpiObjectTypeInfo *info)
function dpiObjectType_getInfo(obj_type_handle::Ptr{Cvoid}, type_info_ref::Ref{OraObjectTypeInfo})
    ccall((:dpiObjectType_getInfo, libdpi), OraResult, (Ptr{Cvoid}, Ref{OraObjectTypeInfo}), obj_type_handle, type_info_ref)
end

#
# ODPI-C Message Properties Functions
#

# int dpiMsgProps_release(dpiMsgProps *props)
function dpiMsgProps_release(msg_props_handle::Ptr{Cvoid})
    ccall((:dpiMsgProps_release, libdpi), OraResult, (Ptr{Cvoid},), msg_props_handle)
end

# int dpiConn_newMsgProps(dpiConn *conn, dpiMsgProps **props)
function dpiConn_newMsgProps(conn_handle::Ptr{Cvoid}, msg_props_handle_ref::Ref{Ptr{Cvoid}})
    ccall((:dpiConn_newMsgProps, libdpi), OraResult, (Ptr{Cvoid}, Ref{Ptr{Cvoid}}), conn_handle, msg_props_handle_ref)
end

# int dpiMsgProps_setPayloadBytes(dpiMsgProps *props, const char *value, uint32_t valueLength)
function dpiMsgProps_setPayloadBytes(msg_props_handle::Ptr{Cvoid}, bytes::Ptr{UInt8}, len::Integer)
    ccall((:dpiMsgProps_setPayloadBytes, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32), msg_props_handle, bytes, len)
end

# int dpiMsgProps_getPayload(dpiMsgProps *props, dpiObject **obj, const char **value, uint32_t *valueLength)
function dpiMsgProps_getPayload(msg_props_handle::Ptr{Cvoid}, obj_handle_ref::Ref{Ptr{Cvoid}}, bytes_ptr_ref::Ref{Ptr{UInt8}}, bytes_len_ref::Ref{UInt32})
    ccall((:dpiMsgProps_getPayload, libdpi), OraResult, (Ptr{Cvoid}, Ref{Ptr{Cvoid}}, Ref{Ptr{UInt8}}, Ref{UInt32}), msg_props_handle, obj_handle_ref, bytes_ptr_ref, bytes_len_ref)
end

# int dpiMsgProps_setCorrelation(dpiMsgProps *props, const char *value, uint32_t valueLength)
function dpiMsgProps_setCorrelation(msg_handle::Ptr{Cvoid}, val::Ptr{UInt8}, val_length::Integer)
    ccall((:dpiMsgProps_setCorrelation, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32), msg_handle, val, val_length)
end

# int dpiMsgProps_getCorrelation(dpiMsgProps *props, const char **value, uint32_t *valueLength)
function dpiMsgProps_getCorrelation(msg_handle::Ptr{Cvoid}, val_ref::Ref{Ptr{UInt8}}, val_length_ref::Ref{UInt32})
    ccall((:dpiMsgProps_getCorrelation, libdpi), OraResult, (Ptr{Cvoid}, Ref{Ptr{UInt8}}, Ref{UInt32}), msg_handle, val_ref, val_length_ref)
end

#
# ODPI-C Queue Functions
#

# int dpiQueue_release(dpiQueue *queue)
function dpiQueue_release(queue_handle::Ptr{Cvoid})
    ccall((:dpiQueue_release, libdpi), OraResult, (Ptr{Cvoid},), queue_handle)
end

# int dpiConn_newQueue(dpiConn *conn, const char *name, uint32_t nameLength, dpiObjectType *payloadType, dpiQueue **queue)
function dpiConn_newQueue(conn_handle::Ptr{Cvoid}, name::AbstractString, payload_type::Ptr{Cvoid}, queue_handle_ref::Ref{Ptr{Cvoid}})
    ccall((:dpiConn_newQueue, libdpi), OraResult, (Ptr{Cvoid}, Ptr{UInt8}, UInt32, Ptr{Cvoid}, Ref{Ptr{Cvoid}}), conn_handle, name, sizeof(name), payload_type, queue_handle_ref)
end

# int dpiQueue_enqOne(dpiQueue *queue, dpiMsgProps *props)
function dpiQueue_enqOne(queue_handle::Ptr{Cvoid}, msg_props_handle::Ptr{Cvoid})
    ccall((:dpiQueue_enqOne, libdpi), OraResult, (Ptr{Cvoid}, Ptr{Cvoid}), queue_handle, msg_props_handle)
end

# int dpiQueue_enqMany(dpiQueue *queue, uint32_t numProps, dpiMsgProps **props)
function dpiQueue_enqMany(queue_handle::Ptr{Cvoid}, num_props::Integer, props_handle_array::Ptr{Ptr{Cvoid}})
    ccall((:dpiQueue_enqMany, libdpi), OraResult, (Ptr{Cvoid}, UInt32, Ptr{Ptr{Cvoid}}), queue_handle, num_props, props_handle_array)
end

# int dpiQueue_deqOne(dpiQueue *queue, dpiMsgProps **props)
function dpiQueue_deqOne(queue_handle::Ptr{Cvoid}, msg_props_handle_ref::Ref{Ptr{Cvoid}})
    ccall((:dpiQueue_deqOne, libdpi), OraResult, (Ptr{Cvoid}, Ref{Ptr{Cvoid}}), queue_handle, msg_props_handle_ref)
end

# int dpiQueue_deqMany(dpiQueue *queue, uint32_t *numProps, dpiMsgProps **props)
function dpiQueue_deqMany(queue_handle::Ptr{Cvoid}, in_out_num_props_ref::Ref{UInt32}, props_handle_array_ptr::Ptr{Ptr{Cvoid}})
    ccall((:dpiQueue_deqMany, libdpi), OraResult, (Ptr{Cvoid}, Ref{UInt32}, Ptr{Ptr{Cvoid}}), queue_handle, in_out_num_props_ref, props_handle_array_ptr)
end


text:
using LinearAlgebra
# using Convex, ECOS, LinearAlgebra
using JuMP
using Ipopt
using Parameters

# using NLopt
## Setting parameters

@with_kw struct Par
    burn::Int64=0 ;
    nsim::Int64=500000 ;
    nfast::Int64=20000 ;
end

Param=Par()

# 1) Warm start ✓
# 2) Chain filling
# 3) Optimization

## Gurobi set up
# ENV["GUROBI_HOME"] = "/Library/gurobi911/mac64"
# ENV["GRB_LICENSE_FILE"]="/Library/gurobi911/mac64/gurobi/gurobi.lic"

## Warm start
# min ||g(x,e)|| st. Inequalities

function warm_start(p,q)
    T,N=size(q)
    wmst=Model(Ipopt.Optimizer)
    set_optimizer_attribute(wmst, "print_level", 0)
    # set_optimizer_attribute(wmst, "algorithm", :LD_SLSQP)
    # Declaring variables
    @variable(wmst, d[1:T,1:N] >= 0) # δ_it Convex cost function c'(q)
    @variable(wmst, 1.0e-16 <= qs[1:T,1:N] <= 1) # unobserved true q_it

    # Non-negative markups
    # @constraint(wmst,mup[t=1:T,j=1:N],d[t,j]<=p[t])
    for j=1:N
        for t=1:T
            set_upper_bound(d[t,j],p[t])
        end
    end

    # Common ratio constraings (p_t-δ_it)/q_it=(p_t-δ_jt)/q_jt
    @NLconstraint(wmst,eq[t=1:T,j=2:N],(p[t]-d[t,1])/qs[t,1]-(p[t]-d[t,j])/qs[t,j]==0)

    # Co-monotone constraint (δ_it'-δ_it)(q_it'-q_it)>=0
    for j=1:N
        @constraint(wmst,[t=1:T,s=1:T],(d[t,j]-d[s,j])*(qs[t,j]-qs[s,j])>=0)
    end

    # Setting objective function
    @NLexpression(wmst, obj, sum((p[t]*(qs[t,j] - q[t,j]))^2 for t=1:T, j=1:N))
    @NLobjective(wmst,Min,obj)

    ## Solving the Model
    JuMP.optimize!(wmst)

    # Checking convergence
    # println("Primal status = ", JuMP.primal_status(wmst))
    JuMP.primal_status(wmst)==MOI.FEASIBLE_POINT || error("Unfeasible point in warm start")
    # Saving variable values
    dsim=value.(d)
    qsim=value.(qs)

    # Memory cleaning
    wmst=nothing
    println("Warm star done.")
    return dsim, qsim
end

## test function

# eδ, eq = warm_start(p=p[1:12],q=q[1:12,1:6])

# it works!

## Build chain

# Getting random direction vector from uniform distribution on the unit sphere

# Compute interval Α to draw uniformly to get α≥0
# Interval Α has to satisfy all constraints
# 1) Sign constraints
# 2) Markup constraints
# 3) Common ratio property
# 4) Co-monotone property

# PLAN B; algorithm
# For time t=0
# 1) Generate random δit ∀i ∈ I at time t=1
# 2) Get random q^*it for a random i and ratio  rt=(pt-δit)/q^*it
# 3) Get q^*jt ∀j≠i (pt-δjt)/rt=q^*jt
# 4) Get ranking
# For time t+1
# 1) Generate random δit sequentially, according to ranking at t=0
# 2) Generate random q^*it for a random i
# 3) get q^*jt ∀j≠i

# For time t=0
# 1) Generate random δit ∀i ∈ I at time t=1

# 1,1) compute interval Α box constraints
function jump_init(p, eδ, eq)
    T, N = size(eδ)
    # Getting random direction vector from uniform distribution on the unit sphere
    v=rand(2,T,N).*2 .-1 # comes from unif*(1-(-1))+(-1)=unif*(ub-lb)+lb
    ξ=v./norm(v) # ξ( δ ,t, i) ξ(q*,t,i)

    αmax=ones(T,N).*1.0e6
    αmin=ones(T,N).*-1.0e6
    α=zeros(N)
    unif=rand(N)

    # Sign constraints for δit
    for i=1:N, t=1:T
        if ξ[1,t,i]<0
            αmax[1,i]=αmax[1,i] < -(eδ[t,i]/ξ[1,t,i]) ? αmax[1,i] : -(eδ[t,i]/ξ[1,t,i])
            αmin[1,i]=αmin[1,i] > (p[t]-eδ[t,i]/ξ[1,t,i]) ? αmin[1,i] : (p[t]-eδ[t,i]/ξ[1,t,i])
        else
            αmax[1,i]=αmax[1,i] < (p[t]-eδ[t,i]/ξ[1,t,i]) ? αmax[1,i] : (p[t]-eδ[t,i]/ξ[1,t,i])
            αmin[1,i]=αmin[1,i] > -(eδ[t,i]/ξ[1,t,i]) ? αmin[1,i] : -(eδ[t,i]/ξ[1,t,i])
        end
    end

    # Sign constraints for q*it
    for i=1:N, t=1:T
        if ξ[2,t,i]<0
            αmax[1,i]=αmax[1,i] < -(eq[t,i]/ξ[2,t,i]) ? αmax[1,i] : -(eq[t,i]/ξ[2,t,i])
        else
            αmin[1,i]=αmin[1,i] > -(eq[t,i]/ξ[2,t,i]) ? αmin[1,i] : -(eq[t,i]/ξ[2,t,i])
        end
    end

    # Co-monotone constraints
    for i=1:N, t=1:T, s=1:T
        t==s && continue
        num=eq[s,i]-eq[t,i]
        den=ξ[2,s,i]-ξ[2,t,i]

        if  den > 0
            αmin[1,i]=αmin[1,i] > -(num/den) ? αmin[1,i] : -(num/den)
        else
            αmax[1,i]=αmax[1,i] < -(num/den) ? αmax[1,i] : -(num/den)
        end

        num=eδ[s,i]-eδ[t,i]
        den=ξ[1,s,i]-ξ[1,t,i]

        if  den > 0
            αmin[1,i]=αmin[1,i] > -(num/den) ? αmin[1,i] : -(num/den)
        else
            αmax[1,i]=αmax[1,i] < -(num/den) ? αmax[1,i] : -(num/den)
        end
    end

    # Draw uniformily from Α
    for i=1:N
        α[i]=αmax[1,i]>αmin[1,i] ? unif[1,i]*(αmax[1,i]-αmin[1,i])+αmin[1,i] : 0.0
    end

    # Generate random δt ∀i in t=0
    δsim=eδ[1,:].+α.*ξ[1,1,:]

    # Common ratio constraint
    qtemp=eq[1,:].+α.*ξ[2,1,:]
    # Pick a country i at random for
    pick=rand(collect(1:N))
    r=(p[1]-δsim[pick])/qtemp[pick]

    qsim=(p[1].-δsim)./r

    ## Check inequalities
    # check=[(δsim[t,i]-δsim[s,i])*(qsim[t,i]-qsim[s,i]) for t=1:T, s=1:T, i=1:N]
    # minimum(check)>=0 || error("Init: Co-monotone inequalities are not satisfied!")
    #

    return δsim, qsim, αmax, αmin, ξ
end
#
# ## Testing get_delta0 function
#
# δ0, q0=get_delta0()
#
#
# (p[1].-δ0)./q0 # Worked!
## jump function

@everywhere function jump(;p=p[1:12], q=q[1:12,1:6], eδ=eδ, eq=eq)
    T, N = size(eδ)
    # Getting random direction vector from uniform distribution on the unit sphere
    v=rand(2,T,N)
    v=v.*2 .-1 # comes from unif*(1-(-1))+(-1)=unif*(ub-lb)+lb
    ξ=v./norm(v) # ξ( δ ,t, i) ξ(q*,t,i)

    αmax=ones(T,N).*1.0e6
    αmin=ones(T,N).*-1.0e6
    α=zeros(N)
    unif=rand(N)

    # Sign constraints for δit
    for i=1:N, t=1:T
        if ξ[1,t,i]<0
            αmax[1,i]=αmax[1,i] < -(eδ[t,i]/ξ[1,t,i]) ? αmax[1,i] : -(eδ[t,i]/ξ[1,t,i])
            αmin[1,i]=αmin[1,i] > (p[t]-eδ[t,i]/ξ[1,t,i]) ? αmin[1,i] : (p[t]-eδ[t,i]/ξ[1,t,i])
        else
            αmax[1,i]=αmax[1,i] < (p[t]-eδ[t,i]/ξ[1,t,i]) ? αmax[1,i] : (p[t]-eδ[t,i]/ξ[1,t,i])
            αmin[1,i]=αmin[1,i] > -(eδ[t,i]/ξ[1,t,i]) ? αmin[1,i] : -(eδ[t,i]/ξ[1,t,i])
        end
    end

    # Sign constraints for q*it
    for i=1:N, t=1:T
        if ξ[2,t,i]<0
            αmax[1,i]=αmax[1,i] < -(eq[t,i]/ξ[2,t,i]) ? αmax[1,i] : -(eq[t,i]/ξ[2,t,i])
        else
            αmin[1,i]=αmin[1,i] > -(eq[t,i]/ξ[2,t,i]) ? αmin[1,i] : -(eq[t,i]/ξ[2,t,i])
        end
    end

    # Co-monotone constraints
    for i=1:N, t=1:T, s=1:T
        t==s && continue
        num=eq[s,i]-eq[t,i]
        den=ξ[2,s,i]-ξ[2,t,i]

        if  den > 0
            αmin[1,i]=αmin[1,i] > -(num/den) ? αmin[1,i] : -(num/den)
        else
            αmax[1,i]=αmax[1,i] < -(num/den) ? αmax[1,i] : -(num/den)
        end

        num=eδ[s,i]-eδ[t,i]
        den=ξ[1,s,i]-ξ[1,t,i]

        if  den > 0
            αmin[1,i]=αmin[1,i] > -(num/den) ? αmin[1,i] : -(num/den)
        else
            αmax[1,i]=αmax[1,i] < -(num/den) ? αmax[1,i] : -(num/den)
        end
    end

    # Draw uniformily from Α
    for i=1:N
        α[i]=αmax[1,i]>αmin[1,i] ? unif[1,i]*(αmax[1,i]-αmin[1,i])+αmin[1,i] : 0.0
    end

    # Generate random δt ∀i in t=0
    δsim=eδ.+α'.*ξ[1,:,:]

    # Common ratio constraint
    qtemp=eq.+α'.*ξ[2,:,:]
    # Pick a country i at random for every t
    pick=rand(collect(1:N),T)
    # estimate ratio for every t
    r=[(p[t]-δsim[t,i])/qtemp[t,i] for (t,i) ∈ zip(collect(1:T), pick)]
    # Use Common ratio property to estimate q^* for every i and t
    qsim=(p.-δsim)./r

    ## Check inequalities
    check=[(δsim[t,i]-δsim[s,i])*(qsim[t,i]-qsim[s,i]) for t=1:T, s=1:T, i=1:N]
    minimum(check)>=0 || error("Init: Co-monotone inequalities are not satisfied!")

    # Estimate W
    w=q.-qsim

    return w, δsim, qsim
end

## testing

# w, δ, qs = jump()
# w1, δ1, qs1 = jump()
#
# w.==w1

##

function ejump(p, q, eδ, eq)
    T, N = size(eδ)
    δ0, q0, αmax, αmin, ξ = jump_init(p, eδ, eq)
    # Initializing arrays
    δsim=zeros(T,N)
    qsim=zeros(T,N)
    α=zeros(N)
    unif=rand(T,N)
    δsim[1,:]=δ0
    qsim[1,:]=q0

    # 4) Get ranking
    rank=indexin(sort(δ0, rev=true),δ0)
    # For time t+1
    # 1) Generate random δit sequentially, according to ranking at t=0

    # random draw for δ1
    b=rank[1] # pick the best firm/country from t=0
    α[1]=αmax[1,b]>αmin[1,b] ? unif[1,b]*(αmax[1,b]-αmin[1,b])+αmin[1,b] : 0.0
    δsim[:,b]=eδ[:,b]+α[1]*ξ[1,:,b]

    for h=2:T # For t=1,...,T
        for i=2:N
            j, k = rank[i-1], rank[i]

            for t=1:T
                # Sign constraints for δit
                if ξ[1,t,k]<0
                    αmax[h,k]=αmax[h,k] < (δsim[h,j]-eδ[t,k])/ξ[1,t,k] ? αmax[h,k] : (δsim[h,j]-eδ[t,k])/ξ[1,t,k]
                    αmin[h,k]=αmin[h,k] > (p[t]-eδ[t,k]/ξ[1,t,k]) ? αmin[h,k] : (p[t]-eδ[t,k]/ξ[1,t,k])
                else
                    αmax[h,k]=αmax[h,k] < (p[t]-eδ[t,k]/ξ[1,t,k]) ? αmax[h,k] : (p[t]-eδ[t,k]/ξ[1,t,k])
                    αmin[h,k]=αmin[h,k] > (δsim[h,j]-eδ[t,k])/ξ[1,t,k] ? αmin[h,k] : (δsim[h,j]-eδ[t,k])/ξ[1,t,k]
                end

                # Sign constraints for q^*it
                if ξ[2,t,k]<0
                    αmax[h,k]=αmax[1,k] < -(eq[t,k]/ξ[2,t,k]) ? αmax[1,k] : -(eq[t,k]/ξ[2,t,k])
                    # αmin[h,k]=αmin[h,k] > (qsim[t,j]-eq[t,k])/ξ[2,t,k] ? αmin[h,k] : (qsim[t,j]-eq[t,k])/ξ[2,t,k]
                else
                    αmin[h,k]=αmin[1,k] > -(eq[t,k]/ξ[2,t,k]) ? αmin[1,k] : -(eq[t,k]/ξ[2,t,k])
                    # αmax[h,k]=αmax[h,k] < (qsim[t,j]-eq[t,k])/ξ[2,t,k] ? αmax[h,k] : (qsim[t,j]-eq[t,k])/ξ[2,t,k]
                end

                # Co-monotone constraints
                for s=1:T
                    t==s && continue
                    # q
                    num=eq[s,k]-eq[t,k]
                    den=ξ[2,s,k]-ξ[2,t,k]

                    if  den > 0
                        αmin[h,k]=αmin[h,k] > -(num/den) ? αmin[h,k] : -(num/den)
                    else
                        αmax[h,k]=αmax[h,k] < -(num/den) ? αmax[h,k] : -(num/den)
                    end

                    # δ
                    num=eδ[s,k]-eδ[t,k]
                    den=ξ[1,s,k]-ξ[1,t,k]

                    if  den > 0
                        αmin[h,k]=αmin[h,k] > -(num/den) ? αmin[h,k] : -(num/den)
                    else
                        αmax[h,k]=αmax[h,k] < -(num/den) ? αmax[h,k] : -(num/den)
                    end
                end
            end

            # Draw uniformily from Α
            α[k]=αmax[h,k]>αmin[h,k] ? unif[h,k]*(αmax[h,k]-αmin[h,k])+αmin[h,k] : 0.0
            # Generate random δt ∀i in t
            δsim[h,k]=eq[h,k]+α[k]*ξ[1,h,k]
        end

        # Common ratio constraint
        # 2) Generate random q^*it for a random i
        qtemp=eq[h,:].+α.*ξ[2,h,:]
        # Pick a country i at random to generate ratio
        pick=rand(collect(1:N))
        r=(p[h]-δsim[h,pick])/qtemp[pick]
        # 3) get q^*jt ∀j≠i
        # Generate q^*jt for j≠i
        qsim[h,:]=(p[h].-δsim[h,:])./r
    end

    ## Check inequalities
    check=[(δsim[t,i]-δsim[s,i])*(qsim[t,i]-qsim[s,i]) for t=1:T, s=1:T, i=1:N]
    minimum(check)>=0 || error("Co-monotone inequalities are not satisfied!")

    W=q-qsim

    return  W, δsim, qsim
end

## Test

# W, dsim, qsim = get_deltat()

# eδ, eq = warm_start(p[1:12],q[1:12,1:6])

## Fill in MCMC Markov Chain Monte Carlo integration

function gchain(p, q; Par::Par=Param, eδ=eδ, eq=eq)
    @unpack burn, nsim = Par
    T, N = size(q)
    # eδ, eq = warm_start()
    ew=eq-q
    mchain=zeros((nsim-burn),N)
    for r=burn+1:nsim
        # W, δsim, qsim = ejump(p, q, eδ, eq)
        W, δsim, qsim = jump(p=p, q=q, eδ=eδ, eq=eq)
        logtrydens = norm(p.*W)-norm(p.*ew)

        if logtrydens.>log.(rand())
            ew=W
            eδ=δsim
            eq=qsim
        end

        mchain[r-burn,:]=gM(p,ew)

    end
    println("Chain is ready.")
    return mchain
end

## Testing chain

# mchain = gchain(p[1:12],q[1:12,1:6])

ext: jl

max_stars_repo_name: hans-mtz/SCR

max_issues_repo_name: hans-mtz/SCR

max_forks_repo_name: hans-mtz/SCR


text:
## State updates ##

function update!(interpreter::AbstractInterpreter,
                 domain::Domain, state::GenericState, diff::GenericDiff)
    if interpreter.autowiden
        return widen!(interpreter, domain, state, diff)
    end
    union!(state.facts, negate.(diff.del))
    setdiff!(state.facts, diff.del)
    union!(state.facts, diff.add)
    setdiff!(state.facts, negate.(diff.del))
    vals = [evaluate(domain, state, v) for v in values(diff.ops)]
    for (term, val) in zip(keys(diff.ops), vals)
        set_fluent!(state, val, term)
    end
    return state
end

"Widen a state (in-place) with a state difference."
function widen!(interpreter::AbstractInterpreter,
                domain::Domain, state::GenericState, diff::GenericDiff)
    union!(state.facts, negate.(diff.del))
    union!(state.facts, diff.add)
    vals = [evaluate(domain, state, v) for v in values(diff.ops)]
    for (term, val) in zip(keys(diff.ops), vals)
        widened = widen(get_fluent(state, term), val)
        set_fluent!(state, widened, term)
    end
    return state
end

"Widen a state with a state difference."
function widen(interpreter::AbstractInterpreter,
               state::GenericState, diff::Diff)
    return widen!(interpreter, copy(state), diff)
end

"Widen a state (in-place) with another state."
function widen!(domain::AbstractedDomain,
                s1::GenericState, s2::GenericState)
    union!(s1.facts, s2.facts)
    if isempty(get_functions(domain)) return s1 end
    for (term, val) in get_fluents(s2)
        if is_pred(term, domain) continue end
        widened = widen(get_fluent(s1, term), val)
        set_fluent!(s1, widened, term)
    end
    return s1
end

"Widen a state with another state."
widen(domain::AbstractedDomain, s1::GenericState, s2::GenericState) =
    widen!(domain.interpreter, copy(s1), s2)


text:
#debug utils
export check_bdim
function check_bdim(mps::MPS)
    for i = 1:mps.L
        if size(mps[i])!= (mps.bdim[i-1],mps.S,mps.bdim[i])
            print("Array Size Error: Tensor:$i, bdim size is $(mps.bdim[i-1]),$(mps.S),$(mps.bdim[i]), in fact it is $(size(mps[i]))\n")
        end
    end
    return nothing
end

export array
"""
store wave function as a tensor
    Notice: this is a quite costful function if N-> large!!!
"""
function array(mps::MPS;field=1:S)
    norm = Float64(mps*mps)
    ID = CartesianIndices(tuple([field for i=1:N]...))
    tensor = zeros(FloatType,[last(field) for i=1:N]...)
    for id in ID
        tensor[id] = disp(mps,id)
    end
    return tensor
end

max_stars_repo_name: qiyang-ustc/JMPS

max_issues_repo_name: qiyang-ustc/JMPS

max_forks_repo_name: qiyang-ustc/JMPS


text:
"
Author: Daniel O'Connor
Email: dt.oconnor@outlook.com

File of how to use the algorithms currently implemented.
"
include("samplers/tools.jl")
include("samplers/SA.jl")
include("samplers/SVMC.jl")
include("samplers/SVMC_TF.jl")
include("samplers/pimc.jl")
include("dynamic_models/spin_vector_O2_dynamics.jl")

using Random
using ..SA
using ..SVMC
using ..SVMCTF
using ..PIMC
using ..SamplingTools
using ..SpinVectorO2Dynamics
using LinearAlgebra
using DifferentialEquations
using Profile
using BenchmarkTools
using NPZ
using Interpolations
using Plots

function main()
    # test 0 =  SA, test 1 = SVMC, test 2 = SVMCTF, test 3 = PIMC
    test = 3

    # simple PFC problem
    d = 0.1
    N = 2
    h, J = SamplingTools.PFC_dict(d, N=N)

    initial_state = Array{Float64, 1}([-1.0 for i = 1:(2*N)])

    num_samples = 1000
    num_sweeps = 1000
    num_slices = 20
    temp = 0.01226 * 1.380649e-23 / (1e9 * 6.62607015e-34)

    a_sch= 1.0 .- collect(LinRange(0, 1, num_sweeps))
    b_sch= collect(LinRange(0, 1, num_sweeps))

    # schedule_data = npzread("data\\DWAVE_schedule.npz")
    # a_fn = SamplingTools.monotonic_interpolation(schedule_data[:, 1], 0.5.*schedule_data[:, 2])
    # b_fn = SamplingTools.monotonic_interpolation(schedule_data[:, 1], 0.5.*schedule_data[:, 3])
    # a_sch = a_fn.(collect(LinRange(0, 1, num_sweeps)))
    # b_sch = b_fn.(collect(LinRange(0, 1, num_sweeps)))

    # DQA schedule
    a_sch, b_sch = SamplingTools.DQA_schedule(1, 2*N, a_sch, b_sch,
                                              sx=0.2, cx=0.0, c1=0.0)

    if test == 0
        # SIMULATED ANNEALING TEST
        # result = SA.sample(h, J, num_reads=num_samples, num_steps=num_sweeps,
                           # add_xtalk=false, noisy=false)
        result = SA.sample(h, J, num_reads=num_samples, num_steps=num_sweeps,
                           add_xtalk=false, noisy=true,
                           # geometric schedule
                           temp_schedule=exp.(LinRange(log(10), log(0.001), num_sweeps)),
                           initial_state=initial_state)
    elseif test == 1
        # SVMC TEST
        # result = SVMC.sample(h, J, num_reads=num_samples, temp=temp,
        #                      a_sch=a_sch, b_sch=b_sch)
        result = SVMC.sample(h, J, num_reads=num_samples, temp=temp,
                             a_sch=a_sch, b_sch=b_sch, add_xtalk=false,
                             noisy=false, spherical=true,)
                             # initial_state=initial_state)
    elseif test == 2
        # SVMC-TF TEST
        # result = SVMCTF.sample(h, J, num_reads=num_samples, temp=temp,
        #                      a_sch=a_sch, b_sch=b_sch)
        result = SVMCTF.sample(h, J, num_reads=num_samples, temp=temp,
                             a_sch=a_sch, b_sch=b_sch, add_xtalk=false,
                             noisy=false, spherical=true,
                             initial_state=initial_state)
    elseif test == 3
        # if initial state given then it superseeds the pre-anneal
        result = PIMC.sample(h, J, num_reads=num_samples, temp=temp,
                             a_sch=a_sch, b_sch=b_sch, nslices=num_slices;
                             add_xtalk=false, noisy=false, pre_anneal=false,)
                             # initial_state=initial_state)
    end
    print("Transverse field supression factor = $(supression_coeff)\n")
    return  result
end

function main_dynamics()
    d = 0.01
    N = 2
    nspins = 2*N
    h, j = SamplingTools.PFC_dict(d, N=N)
    num_samples = 1000
    temp = 0.01226 * 1.380649e-23 / (1e9 * 6.62607015e-34)
    s = collect(0:0.001:1)
    num_steps = length(s)

    max_field = 1.0
    a_sch= max_field .* (1.0 .- s)
    b_sch= max_field .* s
    a_fn = SamplingTools.monotonic_interpolation(s, a_sch)
    b_fn = SamplingTools.monotonic_interpolation(s, b_sch)

    # schedule_data = npzread("data\\DWAVE_schedule.npz")
    # a_fn = SamplingTools.monotonic_interpolation(schedule_data[:, 1], 0.5.*schedule_data[:, 2])
    # b_fn = SamplingTools.monotonic_interpolation(schedule_data[:, 1], 0.5.*schedule_data[:, 3])
    # a_sch = a_fn.(s)
    # b_sch = b_fn.(s)

    # # DQA schedule
    # a_sch, b_sch = SamplingTools.DQA_schedule(1, 2*N, a_sch, b_sch,
    #                                           sx=0.2, cx=0.0, c1=0.0)
    # # convert to functions
    # a_fn = Dict([(i,  SamplingTools.monotonic_interpolation(s, a_sch[i])) for i=1:nspins])
    # b_fn = Dict([(i,  SamplingTools.monotonic_interpolation(s, b_sch[i])) for i=1:nspins])
    #
    run_time = 1000.0
    anneal_time = 1000.0
    # open system enables multi-threading for parallel computation
    open_sys = true
    friction_constant = 2e-2

    # anneal_time = 1000.0
    results, sol = SpinVectorO2Dynamics.solve(h, j, anneal_time=anneal_time,
                                         run_time=run_time, a_fn=a_fn,
                                         b_fn=b_fn, temp=temp,
                                         friction_constant=friction_constant,
                                         trajectories=num_samples,
                                         open_system=open_sys, abstol=1e-8,
                                         reltol=1e-6)

    # ts is the times at which are saved on the ODE solver
    ts = LinRange(0.0, run_time, num_steps)
    if open_sys
        final_states, energies, occurences = results
        print("Solutions = $(final_states) \n energies = $(energies) \n occurences = $(occurences)")
        med = DifferentialEquations.EnsembleAnalysis.timeseries_point_median(sol, ts)
        # low = DifferentialEquations.EnsembleAnalysis.timeseries_point_quantile(sol, 0.025, ts)
        # high = DifferentialEquations.EnsembleAnalysis.timeseries_point_quantile(sol, 0.975, ts)
        thetas = med[1:(2*N), :]' ./pi
        omegas = med[(2*N + 1):(4*N), :]'
    else
        final_state, energy = results
        print("Solution = $(final_state) \n energy = $(energy) \n final θs = $(sol.u[end].x[1])")
        thetas = zeros(Float64, num_steps, length(h))
        omegas = zeros(Float64, num_steps, length(h))
        for i = 1:num_steps
            thetas[i, :] = sol.u[i].x[1] ./ pi
            omegas[i, :] = sol.u[i].x[2]
        end
    end
    plt1 = plot(ts, thetas, xaxis="t / ns", yaxis="θ / π", legend=false)
    plt2 = plot(ts, omegas, xaxis="t / ns", yaxis="ω", legend=false)
    plot(plt1, plt2, layout=(2, 1))
end

max_stars_repo_name: dtoconnor/Annealing-Samplers

max_issues_repo_name: dtoconnor/Annealing-Samplers

max_forks_repo_name: dtoconnor/Annealing-Samplers


text:
using EffectiveWaves, Test
using LinearAlgebra, Statistics

@testset "Check material definitions" begin
    include("../src/acoustics/acoustic_mediums.jl")
    @test true
end

include("complex.jl")

# Single effective wavenumber tests
    @time include("effective-2D/strong_low_freq_effective.jl")
    @time include("effective-2D/high_frequency_effective.jl")

    @time include("effective-2D/large_vol_low_freq_effective.jl")
    @time include("effective-2D/weak_scatterers_effective.jl")

# Eigensystems for different symmetries (i.e. a sphere fille with particles or a halfspace filled with particles)
    @time include("effective-3D/equivalent-symmetries.jl")
    @time include("effective-3D/low_volume_fraction.jl")
    @time include("effective-3D/low_frequency.jl")
    @time include("effective-3D/planar-symmetry.jl")

# test equivalence between methods for finding wavenumbers
    # test does not run on Julia version < 0.7 due to differences in Optim versions
    # include("path_mesh_wavenumbers.jl")

# Test functions used for the discretisation
    include("discretisation/numerical_integration.jl")
    include("discretisation/integrated_reflection.jl")
    include("discretisation/average_integrand_kernel.jl")

# Test discretisation for 3D
    include("effective-3D/discrete_solver.jl")

# Test matching method
    include("match-wave/match_low_volumefraction.jl")
    include("match-wave/match_low_frequency.jl")
    include("match-wave/match_discrete_wave.jl")

# Test wiener hopf method for monopole scatterers
    # include("wiener-hopf-reflection.jl")
    # include("wiener-hopf-wave.jl")


text:
#!/usr/bin/env julia
using Arpack
using LinearAlgebra
using TimerOutputs

# Data structures to represent the block and enlarged block objects.
struct Block
    length::Int
    basis_size::Int
    op_dict::Dict{Symbol,AbstractMatrix{Float64}}
end

struct EnlargedBlock
    length::Int
    basis_size::Int
    op_dict::Dict{Symbol,AbstractMatrix{Float64}}
end

"""
    isvalid(block::Union{Block,EnlargedBlock})

The basis size must match the dimension of each operator matrix.
"""
function isvalid(block::Union{Block,EnlargedBlock})
    all(op -> size(op) == (block.basis_size, block.basis_size),
        values(block.op_dict))
end

"""
       H2(Sz1, Sp1, Sz2, Sp2)

Given the operators S^z and S^+ on two sites in two blocks (sys/env),
returns a Kronecker product representing the corresponding term in the Hamiltonian.
"""
function H2(Sz1, Sp1, Sz2, Sp2;J=1.0,Jz=1.0)  # two-site part of H
    return (J/2.0) * (kron(Sp1, Sp2') + kron(Sp1', Sp2)) + Jz * kron(Sz1, Sz2)
end

function spbHkron!(spbH,tH,sys_enl_op,I_sys_enl,env_enl_op,I_env_enl,to;
                   J=1.0,Jz=1.0)
    #superblock_hamiltonian = kron(sys_enl_op[:H], I_env_enl)
    # + kron(I_sys_enl, env_enl_op[:H])
    # + H2(sys_enl_op[:conn_Sz], sys_enl_op[:conn_Sp],
    #      env_enl_op[:conn_Sz], env_enl_op[:conn_Sp])
    mykron!(spbH,sys_enl_op[:H], I_env_enl)
    mykron_add!(spbH,I_sys_enl,env_enl_op[:H])
    Sz1=sys_enl_op[:conn_Sz]; Sp1=sys_enl_op[:conn_Sp]
    Sz2=env_enl_op[:conn_Sz]; Sp2=env_enl_op[:conn_Sp]
    mykron_add!(spbH,Sp1,Sp2';fac=0.5*J)
    mykron_add!(spbH,Sp1',Sp2;fac=0.5*J)
    mykron_add!(spbH,Sz1, Sz2;fac=Jz)
    return nothing
end

function mykron!(ret,A,B)
    i1,j1 = size(A);i2,j2= size(B)
    @inbounds @simd for j= 1:j1
        for i = 1:i1
            Mat = @views ret[(i-1)*i2+1:i*i2,(j-1)*j2+1:j*j2]
            Mat .= A[i,j] .* B
        end
    end
    return nothing
end
function mykron_add!(ret,A,B;fac=1.0)
    i1,j1 = size(A);i2,j2= size(B)
    @inbounds @simd for j= 1:j1
        for i = 1:i1
            coeff = fac .* A[i,j]
            Mat = @views ret[(i-1)*i2+1:i*i2,(j-1)*j2+1:j*j2]
            Mat .+= coeff .* B
        end
    end
    return nothing
end

"""
    enlarge_block(block::Block)

Enlarges the given Block by a single site => EnlargedBlock
"""
function enlarge_block(block::Block)
    mblock = block.basis_size
    o = block.op_dict
    I1 = Matrix{Float64}(I,model_d,model_d)
    I_block = Matrix{Float64}(I,mblock,mblock)
    enlarged_op_dict = Dict{Symbol,AbstractMatrix{Float64}}(
        :H => kron(o[:H], I1) + kron(I_block, H1) + H2(o[:conn_Sz], o[:conn_Sp], Sz1, Sp1),
        :conn_Sz => kron(I_block, Sz1),:conn_Sp => kron(I_block, Sp1), )
    return EnlargedBlock(block.length + 1,
                         block.basis_size * model_d,
                         enlarged_op_dict)
end

"""
    rotate_and_truncate(operator, U)

Transforms the operator to the new (possibly truncated) basis given by `U`.
U^TOU
"""
function rotate_and_truncate(operator, U)
    return U' * (operator * U)
end

function make_Hermite!(spbH,Dim)
    @inbounds @simd for i = 1:Dim
        for j=i+1:Dim
            tmp = 0.5 * (spbH[i,j] + spbH[j,i])
            spbH[i,j] = tmp; spbH[j,i]=tmp
        end
    end
    return nothing
end

"""
    single_dmrg_step(sys::Block, env::Block, m::Int)

Performs a single DMRG step using `sys` as the system and `env` as the
environment, keeping a maximum of `m` states in the new basis.

spbH = (spbH +spbH')/2 is needed to ensure Hermitian
"""
function single_dmrg_step(sys::Block, env::Block, m::Int, spbH, tmpH, to)
    @assert isvalid(sys); @assert isvalid(env)
    @timeit to "enlarge" begin
        # Enlarge each block by a single site.
        sys_enl = enlarge_block(sys)
        if sys === env
            env_enl = sys_enl
        else
            env_enl = enlarge_block(env)
        end
    end
    @assert isvalid(sys_enl); @assert isvalid(env_enl)

    @timeit to "superblock" begin
        # Construct the superblock Hamiltonian.
        m_sys_enl = sys_enl.basis_size
        m_env_enl = env_enl.basis_size
        sys_enl_op = sys_enl.op_dict
        env_enl_op = env_enl.op_dict
        I_sys_enl = Matrix{Float64}(I,m_sys_enl,m_sys_enl)
        I_env_enl = Matrix{Float64}(I,m_env_enl,m_env_enl)
        tDim = m_sys_enl * m_env_enl
        subH = @views spbH[1:tDim,1:tDim]
        tH   = @views tmpH[1:tDim,1:tDim]
        spbHkron!(subH,tH,sys_enl_op,I_sys_enl,
                  env_enl_op,I_env_enl,to)
        make_Hermite!(subH,m_sys_enl^2)
    end
    @timeit to "Schur decomposition" begin
        @timeit to "eigs" (energy,), psi0 = eigs(subH, nev=1, which=:SR)
        # rho: reduced density matrix of the system (by tracing out the "env")
        psi0 = transpose(reshape(psi0, (env_enl.basis_size, sys_enl.basis_size)))
        tDim = min(tDim,size(psi0)[1])
        rho = @views tmpH[1:tDim,1:tDim]
        mul!(rho,psi0,psi0')
        make_Hermite!(rho,tDim)
        fact = eigen(rho)
        evals, evecs = fact.values, fact.vectors
        permutation = sortperm(evals, rev=true)

        my_m = min(length(evals), m)
        indices = @views permutation[1:my_m]
        U = @views evecs[:,indices]

        truncation_error = 1.0 - sum(evals[indices])

        # Rotate and truncate each operator.
        new_op_dict = Dict{Symbol,AbstractMatrix{Float64}}()
        for (name, op) in sys_enl.op_dict
        new_op_dict[name] = rotate_and_truncate(op, U)
        end
        newblock = Block(sys_enl.length, my_m, new_op_dict)
    end

    return newblock, energy, truncation_error
end

function infinite_system_algorithm(L::Int, m::Int,initial_block,to)
    block = initial_block
    spbH = zeros(Float64,(2*m)^2,(2*m)^2) # superblock Hamiltonian
    tmpH = zeros(Float64,(2*m)^2,(2*m)^2) # matrix for efficient kron!()
    while 2 * block.length < L
        block, energy, trerr = single_dmrg_step(block, block, m, spbH, tmpH, to)
        println("L = ", block.length * 2 + 2, "\t",
                "truncation err ", trerr,"\t",
                "E/L = ", energy / (block.length * 2))
    end
end

function finite_system_algorithm(L::Int, m_warmup::Int,
                                 initial_block, m_sweep_list,to
                                 ;verbose=false)
    if m_sweep_list==[]; m_sweep_list=[m_warmup];end
    @assert iseven(L)
    @timeit to "warmup" begin
        spbH = zeros(Float64,(2*m_warmup)^2,(2*m_warmup)^2) # superblock Hamiltonian
        tmpH = zeros(Float64,(2*m_warmup)^2,(2*m_warmup)^2) # matrix for efficien kron!()

        # "disk" storage for Block objects
        block_disk = Dict{Tuple{Symbol,Int},Block}()
        # Use the infinite system algorithm to build up
        # to desired size. Each time we construct a block,
        # we save it for future reference as both a left
        # (:l) and right (:r) block, as the infinite system algorithm
        # assumes the environment is a mirror image of the system.
        block = initial_block
        block_disk[:l, block.length] = block
        block_disk[:r, block.length] = block
        while 2 * block.length < L
            #println(graphic(block, block))
            block, energy,terr = single_dmrg_step(block, block, m_warmup, spbH, tmpH, to)
            tL = block.length * 2
            if verbose; println("warmup:$tL E/L = ", energy / tL);end
            block_disk[:l, block.length] = block
            block_disk[:r, block.length] = block
        end
    end
    @timeit to "sweep" begin
        sys_label, env_label = :l, :r
        sys_block = block # rename
        block = Block(0, 0, Dict{Symbol,AbstractMatrix{Float64}}())
        for m in m_sweep_list
            while true
                # Load the appropriate environment block from "disk"
                env_block = block_disk[env_label, L - sys_block.length - 2]
                if env_block.length == 1 # "reverse" at the end
                    sys_block, env_block = env_block, sys_block
                    sys_label, env_label = env_label, sys_label
                end
                # Perform a single DMRG step.
                #println(graphic(sys_block, env_block, sys_label))
                sys_block, energy, trerr = single_dmrg_step(sys_block, env_block, m, spbH, tmpH, to)
                if verbose;println("E/L = ", energy / L);end
                # Save the block from this step to disk.
                block_disk[sys_label, sys_block.length] = sys_block
                # Check whether we just completed a full sweep.
                if sys_label == :l && 2 * sys_block.length == L
                    println("L $L E/L = ", energy / L)
                    break  # escape from the "while true" loop
                end
            end
        end
    end
end

# Heisenberg chain
const model_d = 2  # single-site basis size
const Sz1 = [0.5 0.0; 0.0 -0.5]  # single-site S^z
const Sp1 = [0.0 1.0; 0.0 0.0]  # single-site S^+
const H1 = [0.0 0.0; 0.0 0.0]  # single-site portion of H is zero
function main(;L=100,m=20,do_sweep=false,m_sweep_list=[])
    to = TimerOutput()
    initial_block = Block(1, model_d, Dict{Symbol,AbstractMatrix{Float64}}(
        :H => H1,
        :conn_Sz => Sz1,
        :conn_Sp => Sp1,
    ))
    if do_sweep==false
        infinite_system_algorithm(L,m,initial_block,to)
    else
        finite_system_algorithm(L,m,initial_block,m_sweep_list,to)
    end
    #show(to, allocations = true,compact = false);println("")
end

const sL = 100
const sm = 20

main(;L=sL,m=sm)
main(;L=sL,m=sm,do_sweep=true)
for sL = 10:2:200
    main(;L=sL,m=sm,do_sweep=true)
end


text:
using StaticArrays

raw_data = readlines("../inputs/day04_example.txt")

bingo_number_str = raw_data[1]
boards_str = raw_data[3:end]
num_boards = Int((length(boards_str) + 1) / 6)

function vecvec_to_matrix(vecvec)
    dim1 = length(vecvec)
    dim2 = length(vecvec[1])
    my_array = zeros(Int64, dim1, dim2)
    for i = 1:dim1
        for j = 1:dim2
            my_array[i, j] = vecvec[i][j]
        end
    end
    return my_array
end

function board_str2num(lines)
    board_vecvec = [[parse(Int, val) for val in split(line, " ", keepempty = false)] for line in lines]
    return [vecvec_to_matrix(board) for board in board_vecvec]
end

function check_numbers(numbers, board)
    return [board .== num for num in numbers]
end

function check_bingo(numbers, board)
    board_check = check_numbers(numbers, board)
    col_sum = sum(board_check, dims = 1)
    row_sum = sum(board_check, dims = 2)

    return row_sum
end

boards = [board_str2num(boards_str[6*(ii-1)+1:6*(ii-1)+5]) for ii in range(1, num_boards)]

display(boards[1])
println("")
display(boards[2])
println("")
display(boards[3])
println("")

display(check_numbers(boards[2], [10, 16, 15, 9, 19]))


text:
module HyperVolume
#=
Based on the file:
http://ls11-www.cs.uni-dortmund.de/_media/rudolph/hypervolume/hv_python.zip
written in python by Simon Wessing (2010).

This implementation is for the variant 3 detailed in:
C. M. Fonseca, L. Paquete, and M. Lopez-Ibanez. An improved dimension-sweep
algorithm for the hypervolume indicator. In IEEE Congress on Evolutionary
Computation, pages 1157-1163, Vancouver, Canada, July 2006.

=#

include("hypervolume-utils.jl")

"""
Sets up the list data structure needed for calculation.
"""
function preProcess(front, referencePoint)
    dimensions = length(referencePoint)
    sentinel = Node(dimensions)
    sentinel.next = fill(sentinel, dimensions)
    sentinel.prev = fill(sentinel, dimensions)
    nodes = [Node(dimensions, point) for point in front]

    for i in 1:dimensions
        # sortByDimension i
        sort!(nodes, by = node -> node.cargo[i])
        extend!(sentinel,nodes, i)
    end

    return sentinel

end

"""Recursive call to hypervolume calculation.

In contrast to the paper, the code assumes that the reference point
is [0, ..., 0]. This allows the avoidance of a few operations.
"""
function hvRecursive(sentinel, dimIndex, len, bounds)
    hvol = 0.0
    if len == 0
        return hvol
    elseif dimIndex == 1
        # special case: only one dimension
        # why using hypervolume at all?
        return -sentinel.next[1].cargo[1]

    elseif dimIndex == 2
        # special case: two dimensions, end recursion
        q = sentinel.next[2]
        h = q.cargo[1]
        p = q.next[2]

        while !(p === sentinel) #p is not sentinel
            pCargo = p.cargo
            hvol += h * (q.cargo[2] - pCargo[2])
            if pCargo[1] < h
                h = pCargo[1]
            end
            q = p
            p = q.next[2]
        end
        hvol += h * q.cargo[2]
        return hvol
    else
        p = sentinel
        q = p.prev[dimIndex]

        while !isempty(q.cargo) #q.cargo != None
            if q.ignore < dimIndex-1
                q.ignore = 0
            end
            q = q.prev[dimIndex]
        end

        q = p.prev[dimIndex]
        while len > 1 && (
                          q.cargo[dimIndex] > bounds[dimIndex] || q.prev[dimIndex].cargo[dimIndex] >= bounds[dimIndex])
            p = q
            remove!(p, dimIndex, bounds)
            q = p.prev[dimIndex]
            len -= 1
        end

        qArea = q.area
        qCargo = q.cargo
        qPrevDimIndex = q.prev[dimIndex]

        if len > 1
            hvol = qPrevDimIndex.volume[dimIndex]
            hvol += qPrevDimIndex.area[dimIndex] * ( qCargo[dimIndex] - qPrevDimIndex.cargo[dimIndex])
        else
            qArea[1] = 1
            qArea[2:dimIndex] = [qArea[i] * -qCargo[i] for i in 1:dimIndex-1]
        end

        q.volume[dimIndex] = hvol
        if q.ignore >= dimIndex-1
            qArea[dimIndex] = qPrevDimIndex.area[dimIndex]
        else

            qArea[dimIndex] = hvRecursive(sentinel, dimIndex - 1, len, bounds)
            if qArea[dimIndex] <= qPrevDimIndex.area[dimIndex]
                q.ignore = dimIndex-1
            end
        end

        while !(p === sentinel) #p is not sentinel
            pCargoDimIndex = p.cargo[dimIndex]
            hvol += q.area[dimIndex] * (pCargoDimIndex - q.cargo[dimIndex])
            bounds[dimIndex] = pCargoDimIndex
            reinsert!(p, dimIndex, bounds)
            len += 1
            q = p
            p = p.next[dimIndex]
            q.volume[dimIndex] = hvol

            if q.ignore >= dimIndex-1
                q.area[dimIndex] = q.prev[dimIndex].area[dimIndex]
            else
                q.area[dimIndex] = hvRecursive(sentinel, dimIndex - 1, len, bounds)
                if q.area[dimIndex] <= q.prev[dimIndex].area[dimIndex]
                    q.ignore = dimIndex-1
                end
            end

        end
        hvol -= q.area[dimIndex] * q.cargo[dimIndex]
        return hvol

    end

end

function hv(front, referencePoint)
    dimensions = length(referencePoint)

    relevantPoints = [fx - referencePoint for fx in front]
    sentinel = preProcess(relevantPoints, referencePoint)

    bounds = fill(-Inf, dimensions)

    return hvRecursive(sentinel, dimensions, length(relevantPoints), bounds)
end

end


text:
mutable struct GroupStatsCovariate{N, U, S, T<:AbstractFloat} <: AbstractCovariate{T}
    name::String
    length::Int64
    groupstats::GroupStats{N, U, S}
    transform::Function
end

function GroupStatsCovariate(name::String, groupstats::GroupStats{N, U, S}, transform::Function) where {N} where {U} where {S}
    GroupStatsCovariate{N, U, S, Float32}(name, length(groupstats.keyvars[1]), groupstats, transform)
end

function GroupStatsCovariate(name::String, groupstats::GroupStats{N, U, S}) where {N} where {U} where {S}
    GroupStatsCovariate{N, U, S, Float32}(name, length(groupstats.keyvars[1]), groupstats, identity)
end

function GroupStatsCovariate(::Type{T}, name::String, groupstats::GroupStats{N, U, S}, transform::Function) where {T<:AbstractFloat} where {N} where {U} where {S}
    GroupStatsCovariate{N, U, S, T}(name, length(groupstats.keyvars[1]), groupstats, transform)
end

function GroupStatsCovariate(::Type{T}, name::String, groupstats::GroupStats{N, U, S}) where {T<:AbstractFloat} where {N} where {U} where {S}
    GroupStatsCovariate{N, U, S, T}(name, length(groupstats.keyvars[1]), groupstats, identity)
end

function slice(covariate::GroupStatsCovariate{N, U, S, T}, fromobs::Integer, toobs::Integer, slicelength::Integer) where {T<:AbstractFloat} where {N} where {U} where {S}
    keyvars = covariate.groupstats.keyvars
    eltypes = map((x -> eltype(x)), keyvars)
    dict = covariate.groupstats.stats
    slicelength = verifyslicelength(fromobs, toobs, slicelength)
    zipslices = zip(map((v -> slice(v, fromobs, toobs, slicelength)), keyvars))
    f = covariate.transform
    buffer = Vector{T}(undef, slicelength)
    t = zero(T)
    u = zero(U)
    s = zero(S)
    map(zipslices, SubArray{T,1,Array{T,1},Tuple{UnitRange{Int64}},true}) do zipslice
        n = length(zipslice[1])
        if N == 1
            slice = zipslice[1]
            for i in 1:n
                buffer[i] = oftype(t, f(get(dict, (oftype(u, slice[i]), ), s)))
            end
            view(buffer, 1:n)
        elseif N == 2
            slice1, slice2 = zipslice
            for i in 1:n
                buffer[i] = oftype(t, f(get(dict, (oftype(u, slice1[i]), oftype(u, slice2[i])), s)))
            end
            view(buffer, 1:n)
        elseif N == 3
            slice1, slice2, slice3 = zipslice
            for i in 1:n
                buffer[i] = oftype(t, f(get(dict, (oftype(u, slice1[i]), oftype(u, slice2[i]), oftype(u, slice3[i])), s)))
            end
            view(buffer, 1:n)
        elseif N == 4
            slice1, slice2, slice3, slice4 = zipslice
            for i in 1:n
                buffer[i] = oftype(t, f(get(dict, (oftype(u, slice1[i]), oftype(u, slice2[i]), oftype(u, slice3[i]), oftype(u, slice4[i])), s)))
            end
            view(buffer, 1:n)
        else
            for i in 1:n
                buffer[i] = oftype(t, f(get(dict, map((x -> oftype(u, x[i])), zipslice), s)))
            end
            view(buffer, 1:n)
        end
    end
end

function Base.map(covariate::GroupStatsCovariate{N, U, S, T}, dataframe::AbstractDataFrame) where {T<:AbstractFloat} where {N} where {U} where {S}
    mapkeyvars = map(covariate.groupstats.keyvars) do v
        map(v, dataframe; permute = true)
    end
    gstats = GroupStats{N, U, S}(mapkeyvars, covariate.groupstats.covariate, covariate.groupstats.selector, covariate.groupstats.stats)
    GroupStatsCovariate{N, U, S, T}(covariate.name, length(dataframe), gstats, covariate.transform)
end

max_stars_repo_name: Statfactory/JuML

max_issues_repo_name: Statfactory/JuML

max_forks_repo_name: Statfactory/JuML


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

struct AdminConversationsRestrictAccessApi <: SwaggerApi
    client::Swagger.Client
end

function _swaggerinternal_adminConversationsRestrictAccessAddGroup(_api::AdminConversationsRestrictAccessApi, group_id::String, channel_id::String; team_id=nothing, _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", Dict{String, Any}, "/admin.conversations.restrictAccess.addGroup", ["slackAuth"])
    Swagger.set_param(_ctx.form, "team_id", team_id)  # type String
    Swagger.set_param(_ctx.form, "group_id", group_id)  # type String
    Swagger.set_param(_ctx.form, "channel_id", channel_id)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/x-www-form-urlencoded"] : [_mediaType])
    return _ctx
end

"""

Add an allowlist of IDP groups for accessing a channel
Param: group_id::String (required)
Param: channel_id::String (required)
Param: team_id::String
Return: Dict{String, Any}
"""
function adminConversationsRestrictAccessAddGroup(_api::AdminConversationsRestrictAccessApi, group_id::String, channel_id::String; team_id=nothing, _mediaType=nothing)
    _ctx = _swaggerinternal_adminConversationsRestrictAccessAddGroup(_api, group_id, channel_id; team_id=team_id, _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function adminConversationsRestrictAccessAddGroup(_api::AdminConversationsRestrictAccessApi, response_stream::Channel, group_id::String, channel_id::String; team_id=nothing, _mediaType=nothing)
    _ctx = _swaggerinternal_adminConversationsRestrictAccessAddGroup(_api, group_id, channel_id; team_id=team_id, _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

function _swaggerinternal_adminConversationsRestrictAccessListGroups(_api::AdminConversationsRestrictAccessApi, channel_id::String; team_id=nothing, _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", Dict{String, Any}, "/admin.conversations.restrictAccess.listGroups", ["slackAuth"])
    Swagger.set_param(_ctx.query, "channel_id", channel_id)  # type String
    Swagger.set_param(_ctx.query, "team_id", team_id)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/x-www-form-urlencoded"] : [_mediaType])
    return _ctx
end

"""

List all IDP Groups linked to a channel
Param: channel_id::String (required)
Param: team_id::String
Return: Dict{String, Any}
"""
function adminConversationsRestrictAccessListGroups(_api::AdminConversationsRestrictAccessApi, channel_id::String; team_id=nothing, _mediaType=nothing)
    _ctx = _swaggerinternal_adminConversationsRestrictAccessListGroups(_api, channel_id; team_id=team_id, _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function adminConversationsRestrictAccessListGroups(_api::AdminConversationsRestrictAccessApi, response_stream::Channel, channel_id::String; team_id=nothing, _mediaType=nothing)
    _ctx = _swaggerinternal_adminConversationsRestrictAccessListGroups(_api, channel_id; team_id=team_id, _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

function _swaggerinternal_adminConversationsRestrictAccessRemoveGroup(_api::AdminConversationsRestrictAccessApi, team_id::String, group_id::String, channel_id::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "POST", Dict{String, Any}, "/admin.conversations.restrictAccess.removeGroup", ["slackAuth"])
    Swagger.set_param(_ctx.form, "team_id", team_id)  # type String
    Swagger.set_param(_ctx.form, "group_id", group_id)  # type String
    Swagger.set_param(_ctx.form, "channel_id", channel_id)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/x-www-form-urlencoded"] : [_mediaType])
    return _ctx
end

"""

Remove a linked IDP group linked from a private channel
Param: team_id::String (required)
Param: group_id::String (required)
Param: channel_id::String (required)
Return: Dict{String, Any}
"""
function adminConversationsRestrictAccessRemoveGroup(_api::AdminConversationsRestrictAccessApi, team_id::String, group_id::String, channel_id::String; _mediaType=nothing)
    _ctx = _swaggerinternal_adminConversationsRestrictAccessRemoveGroup(_api, team_id, group_id, channel_id; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function adminConversationsRestrictAccessRemoveGroup(_api::AdminConversationsRestrictAccessApi, response_stream::Channel, team_id::String, group_id::String, channel_id::String; _mediaType=nothing)
    _ctx = _swaggerinternal_adminConversationsRestrictAccessRemoveGroup(_api, team_id, group_id, channel_id; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

export adminConversationsRestrictAccessAddGroup, adminConversationsRestrictAccessListGroups, adminConversationsRestrictAccessRemoveGroup


text:
#============
MetaPhlAn CLI
============#

"""
    metaphlan(inputfile, outputfile; kwargs...)

Run `metaphlan` command line tool on `inputfile`,
creating `outputfile`.
Requires `metaphlan` to be installed and accessible in the `PATH`
(see [Getting Started](@ref)).

`metaphlan` options can be passed via keyword arguments.
For example, if on the command line you would run:

```sh
\$ metaphlan some.fastq.gz output/some_profile.tsv --input_type fastq --nproc 8
```

using this function, you would write:

```julia
metaphlan("some.fastq.gz", "output/some_profile.tsv"; input_type="fastq", nproc=8)
```

Note: the `input_type` keyword is required.

Set the environmental variable `"METAPHLAN_BOWTIE2_DB"``
to specify the location where the markergene database is/will be installed,
or pass `bowtie2db = "some/path"` as a keyword argument.
"""
function metaphlan(inputfile, output; kwargs...)
    check_for_install("metaphlan")
    cmd = ["metaphlan", inputfile, output]
    add_cli_kwargs!(cmd, kwargs)

    if !haskey(kwargs, :bowtie2db) && haskey(ENV, "METAPHLAN_BOWTIE2_DB")
        append!(cmd, ["--bowtie2db", ENV["METAPHLAN_BOWTIE2_DB"]])
    end

    deleteat!(cmd, findall(==(""), cmd))
    @info "Running command: $(Cmd(cmd))"
    return run(Cmd(cmd))
end

"""
    metaphlan_merge(paths, outputfile; kwargs...)

Run `merge_metaphlan_tables` command line tool on the files in `paths`,
creating `outputfile`.
Requires `metaphlan` to be installed and accessible in the `PATH`
(see [Getting Started](@ref getting-started)).
"""
function metaphlan_merge(paths, output; kwargs...)
    check_for_install("merge_metaphlan_tables.py")
    cmd = ["merge_metaphlan_tables.py", "-o", output]
    for (key,val) in pairs(kwargs)
        if val isa Bool
            val && push!(cmd, replace(string("--", key), "_"=>"-"))
        elseif val isa AbstractVector
            append!(cmd, [replace(string("--", key), "_"=>"-"), string.(val)...])
        else
            append!(cmd, [replace(string("--", key), "_"=>"-"), string(val)])
        end
    end
    append!(cmd, paths)
    run(Cmd(cmd))
end

#==============
MetaPhlAn Utils
==============#

function _split_ranks(rank_string)
    ranks = split(rank_string, '|')
    taxa = Taxon[]
    for rank in ranks
        push!(taxa, taxon(rank))
    end
    return taxa
end

"""
    metaphlan_profile(path::AbstractString, rank::Union{Int, Symbol}=:all; sample::AbstractString=basename(first(splitext(path))))

Compiles a MetaPhlAn file into a CommunityProfile.
Can select data according to taxonomic rank. If rank not given, all data is compiled.
`Sample name` of the CommunityProfile can be specified by passing a `sample` argument. If name not given, the name of the file becomes the `Sample name`.

Levels may be given either as numbers or symbols:

- `1` = `:kingdom`
- `2` = `:phylum`
- `3` = `:class`
- `4` = `:order`
- `5` = `:family`
- `6` = `:genus`
- `7` = `:species`
- `8` = `:subspecies`
"""
function metaphlan_profile(path::AbstractString, rank=:all; sample=basename(first(splitext(path))))
    if startswith(first(eachline(path)), "#")
        dr = 5
        hd = ["taxon", "NCBI_taxid", "abundance", "additional_species"]
    else
        dr = 2
        hd = ["taxon", "abundance"]
    end
    profile = CSV.read(path, skipto=dr, header=hd, Tables.columntable)
    taxa = [last(_split_ranks(c)) for c in profile.taxon]
    mat = sparse(reshape(profile.abundance, length(profile.abundance), 1))
    sample = sample isa Microbiome.AbstractSample ? sample : MicrobiomeSample(sample)
    keep = rank == :all ? Colon() : [ismissing(c) || c == rank for c in taxrank.(taxa)]
    return CommunityProfile(mat[keep, :], taxa[keep], [sample])
end

function metaphlan_profile(path::AbstractString, rank::Int; sample=basename(first(splitext(path))))
    rank = keys(Microbiome._ranks)[rank]
    metaphlan_profile(path, rank; sample)
end

"""
    metaphlan_profiles(path::AbstractString, rank::Union{Int, Symbol}=:all; keepunidentified=false)

Compiles MetaPhlAn profiles from a merged table into a CommunityProfile.
Can select data according to taxonomic rank. If rank not given, all data is compiled.
Set `keepunidentified` flag to `true` to keep `UNIDENTIFIED` data.

Levels may be given either as numbers or symbols:

- `1` = `:kingdom`
- `2` = `:phylum`
- `3` = `:class`
- `4` = `:order`
- `5` = `:family`
- `6` = `:genus`
- `7` = `:species`
- `8` = `:subspecies`

"""
function metaphlan_profiles(path::AbstractString, rank=:all; samplestart = 2, keepunidentified=false, replace_string="_profile")
    profiles = CSV.read(path, Tables.columntable; comment="#")
    taxa = [last(_split_ranks(c)) for c in profiles[1]]
    mat = reduce(hcat, [sparse(profiles[i]) for i in samplestart:length(profiles)])
    samples = collect(map(s-> MicrobiomeSample(replace(string(s), replace_string => "")), keys(profiles)[samplestart:end]))

    if rank == :all
        keep = Colon()
    elseif keepunidentified
        keep = [ismissing(c) || c == rank for c in taxrank.(taxa)]
    else
        keep = [!ismissing(c) && c == rank for c in taxrank.(taxa)]
    end
    return CommunityProfile(mat[keep, :], taxa[keep], samples)
end

function metaphlan_profiles(path::AbstractString, rank::Int; kwargs...)
    rank = keys(Microbiome._ranks)[rank + 1]
    metaphlan_profiles(path, rank; kwargs...)
end

"""
    metaphlan_profiles(paths::Array{<:AbstractString, 1}, rank::Union{Int, Symbol}=:all)

Compiles MetaPhlAn profiles from multiple single tables into a CommunityProfile.
"""
function metaphlan_profiles(paths::Array{<:AbstractString, 1}, rank=:all; samples=nothing)
    if isnothing(samples)
        samples = [first(splitext(basename(f))) for f in paths]
    else
        length(samples) == length(paths) || throw(ArgumentError("Number of paths ($(length(paths))) and number of samples ($(length(samples))) does not match"))
    end
    profiles = []
    for (path, sample) in zip(paths, samples)
        push!(profiles, metaphlan_profile(path, rank; sample))
    end
    commjoin(profiles...)
end

function metaphlan_profiles(paths::Array{<:AbstractString, 1}, rank::Int; samples=nothing)
    rank = keys(Microbiome._ranks)[rank + 1]
    metaphlan_profiles(paths, rank; samples)
end

"""
    parsetaxon(taxstring::AbstractString, rank::Union{Int, Symbol})

Finds given taxonomic rank in a string (as formatted by MetaPhlAn (eg "k__Bacteria|p__Proteobacteria..."))
and returns the name and taxonomic rank as a `Taxon`.
If taxon rank not given, function will return the most specific (lowest) taxonomic rank available.

Levels may be given either as numbers or symbols:

- `1` = `:kingdom`
- `2` = `:phylum`
- `3` = `:class`
- `4` = `:order`
- `5` = `:family`
- `6` = `:genus`
- `7` = `:species`
- `8` = `:subspecies`
"""
function parsetaxon(taxstring::AbstractString; throw_error=true)
    taxa = parsetaxa(taxstring, throw_error=throw_error)
    return last(taxa)
end

function parsetaxon(taxstring::AbstractString, rank::Int; throw_error=true)
    taxa = parsetaxa(taxstring, throw_error=throw_error)
    rank <= length(taxa) || throw(ArgumentError("Taxonomy does not contain rank $rank"))
    return taxa[rank]
end

parsetaxon(taxstring::AbstractString, rank::Symbol) = parsetaxon(taxstring, Microbiome._ranks[rank])

"""
    parsetaxa(taxstring::AbstractString; throw_error=true)

Given a string representing taxonmic ranks as formatted by MetaPhlAn (eg "k__Bacteria|p__Proteobacteria..."),
separates taxonomic ranks into elements of type Taxon in a vector.
"""
function parsetaxa(taxstring::AbstractString; throw_error=true)
    taxa = split(taxstring, '|')
    return map(t-> Taxon(t...), _shortname.(taxa, throw_error=throw_error))
end

function _shortname(taxon::AbstractString; throw_error=true)
    m = match(r"^[kpcofgst]__(\w+)$", taxon)
    if isnothing(m)
        throw_error ? throw(ArgumentError("Improperly formated taxon $taxon")) : return (string(taxon), :unidentified)
    end
    return string(m.captures[1]), Microbiome._shortranks[Symbol(first(taxon))]
end

max_stars_repo_name: BioJulia/BiobakeryUtils

max_issues_repo_name: BioJulia/BiobakeryUtils

max_forks_repo_name: BioJulia/BiobakeryUtils


text:
module Ex5_12
using FaultDetectionTools
using DescriptorSystems
using LinearAlgebra
using Polynomials
using Test

# Example 5.12 - Solution of an EMMP
println("Example 5.12")

# enter output and fault vector dimensions
p = 3; mf = 3;
# generate random dimensions for system order and input vectors
nu = Int(floor(1+4*rand())); mu = Int(floor(1+4*rand()));
nd = Int(floor(1+4*rand())); md = Int(floor(1+4*rand()));

# define random Gu(s) and Gd(s) with triplex sensor redundancy
# and Gf(s) for triplex sensor faults
Gu = ones(3,1)*rss(nu,1,mu); # enter Gu(s) in state-space form
Gd = ones(3,1)*rss(nd,1,md); # enter Gd(s) in state-space form
Gf = eye(3);                 # enter Gf(s) for sensor faults
atol = 1.e-7;                # tolerance for rank tests

# build model with faults
#sysf = [Gu Gd Gf]
sysf = fdimodset([Gu Gd Gf], c = 1:mu, d = mu.+(1:md), f = (mu+md).+(1:mf))

# enter reference model
Mr = dss([ 0 1 -1; -1 0 1; 1 -1 0]);

# two step solution using Procedure EMM
# 1. Compute left nullspace and the reduced system
Q_Rf, info = glnull([sysf.sys; eye(mu,mu+md+mf)], mf; atol)

# Q_Rf = glnull([Gu Gd Gf; eye(mu,mu+md+mf)],struct('m2',mf));
Q1 =  Q_Rf[:,1:p+mu]; Rf = Q_Rf[:,p+mu+1:end];

# 2. Solve X*Rf = Mr and update Q
Q2 = glsol(Rf,Mr; atol)[1]
Q = Q2*Q1;

# one step solution
# solve Qbar*Ge = Me, where Ge = [Gu Gd Gf; I 0 0] and Me = [0 0 Mr ].
Ge = [sysf.sys; eye(mu,mu+md+mf)]; Me = [zeros(p,mu+md) Mr];
Qbar = glsol(Ge, Me; atol)[1]

# compare solutions
@test iszero(Q-Qbar; atol)

end # module

max_stars_repo_name: andreasvarga/FaultDetectionTools

max_issues_repo_name: andreasvarga/FaultDetectionTools

max_forks_repo_name: andreasvarga/FaultDetectionTools