diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml index 7144ad0bd7..7fd0ab0ab5 100644 --- a/.ci/linux-steps.yaml +++ b/.ci/linux-steps.yaml @@ -43,7 +43,7 @@ steps: - script: | unset BOOST_ROOT mkdir build && cd build - export GOPATH=$PWD + export GOPATH=$PWD/src/mlpack/bindings/go go get -u -t gonum.org/v1/gonum/... cmake $(CMakeArgs) .. displayName: 'CMake' diff --git a/.ci/macos-steps.yaml b/.ci/macos-steps.yaml index 90e310f91b..b74dffc85f 100644 --- a/.ci/macos-steps.yaml +++ b/.ci/macos-steps.yaml @@ -28,7 +28,7 @@ steps: - script: | unset BOOST_ROOT mkdir build && cd build - export GOPATH=$PWD + export GOPATH=$PWD/src/mlpack/bindings/go go get -u -t gonum.org/v1/gonum/... export PYPATH=$(which python) cmake $(CMakeArgs) -DPYTHON_EXECUTABLE=$PYPATH .. diff --git a/CMake/ConfigureGoHCPP.cmake b/CMake/ConfigureGoHCPP.cmake deleted file mode 100644 index 0f241a149f..0000000000 --- a/CMake/ConfigureGoHCPP.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# ConfigureGoHCPP.cmake: generate an mlpack .h file for a Go binding given -# input arguments. -# -# This file depends on the following variables being set: -# -# * PROGRAM_NAME: name of the binding -# * PROGRAM_MAIN_FILE: the file containing the mlpackMain() function. -# * GENERATE_GO_IN: path of the generate_go.cpp.in file. -# * GENERATE_GO_OUT: name of the output .go file. -# * GENERATE_CPP_IN: path of the generate_cpp.cpp.in file. -# * GENERATE_CPP_OUT: name of the output .cpp file. -# * GENERATE_H_IN: path of the generate_h.cpp.in file. -# * GENERATE_H_OUT: name of the output .h file. -configure_file("${GENERATE_BINDING_IN}" "${GENERATE_BINDING_OUT}") diff --git a/CMake/go/AppendModel.cmake b/CMake/go/AppendModel.cmake new file mode 100644 index 0000000000..bc31fef006 --- /dev/null +++ b/CMake/go/AppendModel.cmake @@ -0,0 +1,116 @@ +# AppendModel.cmake: append model definition and gettter setter methods for +# mlpack model types to the existing file of models.go. + +# This function depends on the following variables being set: +# +# * PROGRAM_MAIN_FILE: the file containing the mlpackMain() function. +# * SERIALIZATION_FILE: file to append types to +# +# We need to parse the main file and find any PARAM_MODEL_* lines. +function(append_model SERIALIZATION_FILE PROGRAM_MAIN_FILE) + file(READ "${PROGRAM_MAIN_FILE}" MAIN_FILE) + + # Grab all "PARAM_MODEL_IN(Model,", "PARAM_MODEL_IN_REQ(Model,", + # "PARAM_MODEL_OUT(Model,". + string(REGEX MATCHALL "PARAM_MODEL_IN\\([A-Za-z_<>]*," MODELS_IN + "${MAIN_FILE}") + string(REGEX MATCHALL "PARAM_MODEL_IN_REQ\\([A-Za-z_<>]*," MODELS_IN_REQ + "${MAIN_FILE}") + string(REGEX MATCHALL "PARAM_MODEL_OUT\\([A-Za-z_]*," MODELS_OUT "${MAIN_FILE}") + + string(REGEX REPLACE "PARAM_MODEL_IN\\(" "" MODELS_IN_STRIP1 "${MODELS_IN}") + string(REGEX REPLACE "," "" MODELS_IN_STRIP2 "${MODELS_IN_STRIP1}") + string(REGEX REPLACE "[<>,]" "" MODELS_IN_SAFE_STRIP2 "${MODELS_IN_STRIP1}") + + string(REGEX REPLACE "PARAM_MODEL_IN_REQ\\(" "" MODELS_IN_REQ_STRIP1 + "${MODELS_IN_REQ}") + string(REGEX REPLACE "," "" MODELS_IN_REQ_STRIP2 "${MODELS_IN_REQ_STRIP1}") + string(REGEX REPLACE "[<>,]" "" MODELS_IN_REQ_SAFE_STRIP2 + "${MODELS_IN_REQ_STRIP1}") + + string(REGEX REPLACE "PARAM_MODEL_OUT\\(" "" MODELS_OUT_STRIP1 "${MODELS_OUT}") + string(REGEX REPLACE "," "" MODELS_OUT_STRIP2 "${MODELS_OUT_STRIP1}") + string(REGEX REPLACE "[<>,]" "" MODELS_OUT_SAFE_STRIP2 "${MODELS_OUT_STRIP1}") + + set(MODEL_TYPES ${MODELS_IN_STRIP2} ${MODELS_IN_REQ_STRIP2} + ${MODELS_OUT_STRIP2}) + set(MODEL_SAFE_TYPES ${MODELS_IN_SAFE_STRIP2} ${MODELS_IN_REQ_SAFE_STRIP2} + ${MODELS_OUT_SAFE_STRIP2}) + if (MODEL_TYPES) + list(REMOVE_DUPLICATES MODEL_TYPES) + endif () + if (MODEL_SAFE_TYPES) + list(REMOVE_DUPLICATES MODEL_SAFE_TYPES) + endif () + + # Now, generate the definitions of the functions we need. + set(MODEL_PTR_DEFNS "") + set(MODEL_PTR_IMPLS "") + list(LENGTH MODEL_TYPES NUM_MODEL_TYPES) + if (${NUM_MODEL_TYPES} GREATER 0) + math(EXPR LOOP_MAX "${NUM_MODEL_TYPES}-1") + foreach (INDEX RANGE ${LOOP_MAX}) + list(GET MODEL_TYPES ${INDEX} MODEL_TYPE) + list(GET MODEL_SAFE_TYPES ${INDEX} MODEL_SAFE_TYPE) + + # Convert the model type similar to goStrippedType(bindings/go/strip_type.hpp). + string(LENGTH ${MODEL_SAFE_TYPE} NUM_MODEL_CHAR) + if (${NUM_MODEL_CHAR} GREATER 0) + math(EXPR LAST_CHAR_INDEX "${NUM_MODEL_CHAR}-1") + set(BREAK 0) + foreach (INDEX RANGE ${LAST_CHAR_INDEX}) + if (NOT "${MODEL_SAFE_TYPE}" MATCHES "[^A-Z]") + string(TOLOWER ${MODEL_SAFE_TYPE} GOMODEL_SAFE_TYPE) + break() + endif() + string(SUBSTRING ${MODEL_SAFE_TYPE} "${INDEX}" "1" MODEL_CHAR) + if (${BREAK} EQUAL 0) + string(TOLOWER ${MODEL_CHAR} MODEL_CHAR) + string(APPEND GOMODEL_SAFE_TYPE ${MODEL_CHAR}) + math(EXPR INDEX1 "${INDEX}+1") + math(EXPR INDEX2 "${INDEX}+2") + string(SUBSTRING "${MODEL_SAFE_TYPE}" "${INDEX1}" "1" MODEL_CHAR1) + string(SUBSTRING "${MODEL_SAFE_TYPE}" "${INDEX2}" "1" MODEL_CHAR2) + if ("${MODEL_CHAR1}" MATCHES "[A-Z]" AND "${MODEL_CHAR2}" MATCHES "[^A-Z]") + set(BREAK 1) + endif() + else () + string(APPEND GOMODEL_SAFE_TYPE ${MODEL_CHAR}) + endif() + endif() + endforeach() + + # See if the model type already exists. + file(READ "${SERIALIZATION_FILE}" SERIALIZATION_FILE_CONTENTS) + string(FIND + "${SERIALIZATION_FILE_CONTENTS}" + "type ${GOMODEL_SAFE_TYPE} struct {\n" + FIND_OUT) + + # If it doesn't exist, append it. + if (${FIND_OUT} EQUAL -1) + # Now append the type to the list of types, and define any serialization + # function. + file(APPEND + "${SERIALIZATION_FILE}" + "type ${GOMODEL_SAFE_TYPE} struct {\n" + " mem unsafe.Pointer \n" + "}\n\n" + "func (m *${GOMODEL_SAFE_TYPE}) alloc" + "${MODEL_SAFE_TYPE}(identifier string) {\n" + " m.mem = C.mlpackGet${MODEL_SAFE_TYPE}Ptr(C.CString(identifier))\n" + " runtime.KeepAlive(m)\n" + "}\n\n" + "func (m *${GOMODEL_SAFE_TYPE}) get" + "${MODEL_SAFE_TYPE}(identifier string) {\n" + " m.alloc${MODEL_SAFE_TYPE}(identifier)\n" + "}\n\n" + "func set${MODEL_SAFE_TYPE}(identifier string, ptr *" + "${GOMODEL_SAFE_TYPE}) {\n" + " C.mlpackSet${MODEL_SAFE_TYPE}" + "Ptr(C.CString(identifier), (unsafe.Pointer)(ptr.mem))\n" + "}\n\n") + endif () + endforeach () + endif() +endfunction() diff --git a/CMake/go/ConfigureGoHCPP.cmake b/CMake/go/ConfigureGoHCPP.cmake new file mode 100644 index 0000000000..cdf4a2df42 --- /dev/null +++ b/CMake/go/ConfigureGoHCPP.cmake @@ -0,0 +1,115 @@ +# ConfigureGoHCPP.cmake: generate an mlpack .h/.cpp file for a Go binding given +# input arguments. +# +# This file depends on the following variables being set: +# +# * PROGRAM_NAME: name of the binding +# * PROGRAM_MAIN_FILE: the file containing the mlpackMain() function. +# * GO_IN: path of the go_method.h.in/go_method.cpp.in file. +# * GO_OUT: name of the output .h/.cpp file. +# +# We need to parse the main file and find any PARAM_MODEL_* lines. +file(READ "${PROGRAM_MAIN_FILE}" MAIN_FILE) + +# Grab all "PARAM_MODEL_IN(Model,", "PARAM_MODEL_IN_REQ(Model,", +# "PARAM_MODEL_OUT(Model,". +string(REGEX MATCHALL "PARAM_MODEL_IN\\([A-Za-z_<>]*," MODELS_IN + "${MAIN_FILE}") +string(REGEX MATCHALL "PARAM_MODEL_IN_REQ\\([A-Za-z_<>]*," MODELS_IN_REQ + "${MAIN_FILE}") +string(REGEX MATCHALL "PARAM_MODEL_OUT\\([A-Za-z_]*," MODELS_OUT "${MAIN_FILE}") + +string(REGEX REPLACE "PARAM_MODEL_IN\\(" "" MODELS_IN_STRIP1 "${MODELS_IN}") +string(REGEX REPLACE "," "" MODELS_IN_STRIP2 "${MODELS_IN_STRIP1}") +string(REGEX REPLACE "[<>,]" "" MODELS_IN_SAFE_STRIP2 "${MODELS_IN_STRIP1}") + +string(REGEX REPLACE "PARAM_MODEL_IN_REQ\\(" "" MODELS_IN_REQ_STRIP1 + "${MODELS_IN_REQ}") +string(REGEX REPLACE "," "" MODELS_IN_REQ_STRIP2 "${MODELS_IN_REQ_STRIP1}") +string(REGEX REPLACE "[<>,]" "" MODELS_IN_REQ_SAFE_STRIP2 + "${MODELS_IN_REQ_STRIP1}") + +string(REGEX REPLACE "PARAM_MODEL_OUT\\(" "" MODELS_OUT_STRIP1 "${MODELS_OUT}") +string(REGEX REPLACE "," "" MODELS_OUT_STRIP2 "${MODELS_OUT_STRIP1}") +string(REGEX REPLACE "[<>,]" "" MODELS_OUT_SAFE_STRIP2 "${MODELS_OUT_STRIP1}") + +set(MODEL_TYPES ${MODELS_IN_STRIP2} ${MODELS_IN_REQ_STRIP2} + ${MODELS_OUT_STRIP2}) +set(MODEL_SAFE_TYPES ${MODELS_IN_SAFE_STRIP2} ${MODELS_IN_REQ_SAFE_STRIP2} + ${MODELS_OUT_SAFE_STRIP2}) +if (MODEL_TYPES) + list(REMOVE_DUPLICATES MODEL_TYPES) +endif () +if (MODEL_SAFE_TYPES) + list(REMOVE_DUPLICATES MODEL_SAFE_TYPES) +endif () + +# Now, generate the definitions of the functions we need. +set(MODEL_PTR_DEFNS "") +set(MODEL_PTR_IMPLS "") +list(LENGTH MODEL_TYPES NUM_MODEL_TYPES) +if (${NUM_MODEL_TYPES} GREATER 0) + math(EXPR LOOP_MAX "${NUM_MODEL_TYPES}-1") + foreach (INDEX RANGE ${LOOP_MAX}) + list(GET MODEL_TYPES ${INDEX} MODEL_TYPE) + list(GET MODEL_SAFE_TYPES ${INDEX} MODEL_SAFE_TYPE) + + # Generate the definition. + set(MODEL_PTR_DEFNS "${MODEL_PTR_DEFNS} +// Set the pointer to a ${MODEL_TYPE} parameter. +extern void mlpackSet${MODEL_SAFE_TYPE}Ptr(const char* identifier, void* value); + +// Get the pointer to a ${MODEL_TYPE} parameter. +extern void* mlpackGet${MODEL_SAFE_TYPE}Ptr(const char* identifier); +" +) + + # Generate the implementation. + set(MODEL_PTR_IMPLS "${MODEL_PTR_IMPLS} +// Set the pointer to a ${MODEL_TYPE} parameter. +extern \"C\" void mlpackSet${MODEL_SAFE_TYPE}Ptr( + const char* identifier, + void* value) +{ + mlpack::util::SetParamPtr<${MODEL_TYPE}>(identifier, + static_cast<${MODEL_TYPE}*>(value)); +} + +// Get the pointer to a ${MODEL_TYPE} parameter. +extern \"C\" void *mlpackGet${MODEL_SAFE_TYPE}Ptr(const char* identifier) +{ + ${MODEL_TYPE} *modelptr = CLI::GetParam<${MODEL_TYPE}*>(identifier); + return modelptr; +} +") + endforeach () +endif() + +# Convert ${PROGRAM_NAME} from snake_case to CamelCase. +string(LENGTH ${PROGRAM_NAME} NUM_MODEL_CHAR) +if (${NUM_MODEL_CHAR} GREATER 0) + math(EXPR LAST_CHAR_INDEX "${NUM_MODEL_CHAR}-2") + string(SUBSTRING ${PROGRAM_NAME} "0" "1" MODEL_CHAR) + string(TOUPPER ${MODEL_CHAR} MODEL_CHAR) + string(APPEND GOPROGRAM_NAME ${MODEL_CHAR}) + foreach (INDEX0 RANGE ${LAST_CHAR_INDEX}) + math(EXPR INDEX0 "${INDEX0}+1") + math(EXPR INDEX1 "${INDEX0}+1") + math(EXPR INDEX2 "${INDEX0}-1") + string(SUBSTRING "${PROGRAM_NAME}" "${INDEX0}" "1" MODEL_CHAR1) + string(SUBSTRING "${PROGRAM_NAME}" "${INDEX1}" "1" MODEL_CHAR2) + string(SUBSTRING "${PROGRAM_NAME}" "${INDEX2}" "1" MODEL_CHAR3) + if ("${MODEL_CHAR1}" MATCHES "_") + string(TOUPPER ${MODEL_CHAR2} MODEL_CHAR2) + string(APPEND GOPROGRAM_NAME ${MODEL_CHAR2}) + set(INDEX0 ${INDEX1}) + elseif ("${MODEL_CHAR3}" MATCHES "_") + continue() + else() + string(APPEND GOPROGRAM_NAME ${MODEL_CHAR1}) + endif() + endforeach() +endif() + +# Now configure the files. +configure_file("${GO_IN}" "${GO_OUT}") diff --git a/HISTORY.md b/HISTORY.md index 96596cc0d3..5336b3cc8e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,10 @@ ###### ????-??-?? * Added N-step DQN to q_networks (#2461). + * Add Silhoutte Score metric and Pairwise Distances (#2406). + + * Add Go bindings for some missed models (#2460). + ### mlpack 3.3.2 ###### 2020-06-18 * Added Noisy DQN to q_networks (#2446). diff --git a/doc/guide/go_quickstart.hpp b/doc/guide/go_quickstart.hpp index 66d22e30a8..b476d1d85d 100644 --- a/doc/guide/go_quickstart.hpp +++ b/doc/guide/go_quickstart.hpp @@ -41,7 +41,7 @@ You can copy-paste this code directly into main.go to run it. package main import ( - "github.com/mlpack.org/v1/mlpack" + "mlpack.org/v1/mlpack" "fmt" ) func main() { @@ -134,7 +134,7 @@ package main import ( "github.com/frictionlessdata/tableschema-go/csv" - "github.com/mlpack.org/v1/mlpack" + "mlpack.org/v1/mlpack" "gonum.org/v1/gonum/mat" "fmt" ) diff --git a/doc/guide/julia_quickstart.hpp b/doc/guide/julia_quickstart.hpp index 5f6fad9921..a63c86e7e1 100644 --- a/doc/guide/julia_quickstart.hpp +++ b/doc/guide/julia_quickstart.hpp @@ -37,7 +37,7 @@ print the accuracy of the random forest on the test dataset. You can copy-paste this code directly into Julia to run it. You may need to add some extra packages with, e.g., `using Pkg; Pkg.add("CSV"); -Pkg.add("DataFrames"); Pkg.add("Zlib")`. +Pkg.add("DataFrames"); Pkg.add("Libz")`. @code{.julia} using CSV @@ -56,7 +56,7 @@ dataset = select!(df, Not(:label)) # Split the dataset using mlpack. test, test_labels, train, train_labels = mlpack.preprocess_split( - input=dataset, + dataset, input_labels=labels, test_ratio=0.3) diff --git a/src/mlpack/CMakeLists.txt b/src/mlpack/CMakeLists.txt index ebfec2b6a6..a3895c33c8 100644 --- a/src/mlpack/CMakeLists.txt +++ b/src/mlpack/CMakeLists.txt @@ -156,6 +156,29 @@ if (BUILD_JULIA_BINDINGS) "\nend\ninclude(\"functions.jl\")\ninclude(\"serialization.jl\")\nend\n") endif () + +# If we are building Go bindings, we have to end the 'module' declaration in +# models.go +if (BUILD_GO_BINDINGS) + file(APPEND + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/models.go" + "*/\n" + "import \"C\"\n\n" + "import (\n" + " \"runtime\"\n" + " \"unsafe\"\n" + ")\n\n") + + include("${CMAKE_SOURCE_DIR}/CMake/go/AppendModel.cmake") + # Read list content. + get_property(MODELS GLOBAL PROPERTY GO_MODELS) + foreach (models IN LISTS MODELS) + append_model( + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/models.go" + ${models}) + endforeach() +endif() + # If we are building Markdown documentation, we have to run some setup after we # recurse into methods/. If not, this function is empty. post_markdown_setup() diff --git a/src/mlpack/bindings/go/CMakeLists.txt b/src/mlpack/bindings/go/CMakeLists.txt index fabce0c620..fcc1cde9b4 100644 --- a/src/mlpack/bindings/go/CMakeLists.txt +++ b/src/mlpack/bindings/go/CMakeLists.txt @@ -24,6 +24,7 @@ if (BUILD_GO_BINDINGS) find_package(Gonum) if (NOT GO_FOUND OR NOT GONUM_FOUND) unset(BUILD_GO_BINDINGS CACHE) + set(BUILD_GO_SHLIB OFF) message(FATAL_ERROR "Go or Gonum not found; unable to build Go bindings!") endif() else () @@ -31,6 +32,7 @@ if (BUILD_GO_BINDINGS) find_package(Gonum) if (NOT GO_FOUND OR NOT GONUM_FOUND) unset(BUILD_GO_BINDINGS CACHE) + set(BUILD_GO_SHLIB OFF) endif() endif () @@ -43,6 +45,16 @@ if (BUILD_GO_BINDINGS) endif () add_custom_target(go) + + # All the bindings will build under "src/mlpack.org/v1/mlpack"; So if user build + # go-bindings from source, then he/she can use the same import path as documented + # on "mlpack.org" by setting GOPATH=/path/to/mlpack/build/src/mlpack/bindings/go. + # Create model.go with package definition. + file(WRITE + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/models.go" + "package mlpack" + "\n\n" + "/*\n") endif() if (BUILD_GO_SHLIB) @@ -58,8 +70,6 @@ if (BUILD_GO_SHLIB) mlpack/cli_util.h mlpack/cli_util.hpp print_class_defn.hpp - print_cpp.cpp - print_cpp.hpp print_defn_input.hpp print_defn_output.hpp print_doc.hpp @@ -67,9 +77,6 @@ if (BUILD_GO_SHLIB) print_doc_functions_impl.hpp print_go.hpp print_go.cpp - print_h.hpp - print_h.cpp - print_import_decl.hpp print_input_processing.hpp print_method_config.hpp print_method_init.hpp @@ -85,24 +92,15 @@ if (BUILD_GO_SHLIB) mlpack/cli_util.go mlpack/doc.go mlpack/numcsv.go + mlpack/go.mod + mlpack/go.sum ) # These are all the files we need to compile Go bindings for mlpack that are # not a part of mlpack itself. set(CAPI_SOURCES - mlpack/capi/arma_util.cpp mlpack/capi/arma_util.h - mlpack/capi/arma_util.hpp - mlpack/capi/cli_util.cpp mlpack/capi/cli_util.h - mlpack/capi/cli_util.hpp - ) - - # These are all the files we need to compile Go bindings for mlpack that are - # not a part of mlpack itself. - set(UTIL_SOURCES - mlpack/capi/arma_util.cpp - mlpack/capi/cli_util.cpp ) set(TEST_SOURCES @@ -111,47 +109,50 @@ if (BUILD_GO_SHLIB) add_custom_target(go_shlib ALL DEPENDS mlpack) add_custom_target(go_copy ALL DEPENDS mlpack) - if (BUILD_TESTS OR BUILD_GO_SHLIB) - foreach(test_file ${TEST_SOURCES}) - add_custom_command(TARGET go_copy PRE_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different - ${CMAKE_CURRENT_SOURCE_DIR}/${test_file} - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/tests/) - endforeach () - endif () - # Copy necessary files after making the mlpack/ directory. add_custom_command(TARGET go_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/ + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/ COMMAND ${CMAKE_COMMAND} -E make_directory - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/capi/) + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/capi/ + COMMAND ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/tests/) + foreach(go_file ${CAPI_SOURCES}) add_custom_command(TARGET go_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${go_file} - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/capi/) + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/capi/) endforeach() add_custom_command(TARGET go_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different $ - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/) + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/) foreach(cgo_file ${CGO_SOURCES}) add_custom_command(TARGET go_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${cgo_file} - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/) + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/) endforeach() + if (BUILD_TESTS OR BUILD_GO_SHLIB) + foreach(test_file ${TEST_SOURCES}) + add_custom_command(TARGET go_copy PRE_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different + ${CMAKE_CURRENT_SOURCE_DIR}/${test_file} + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/tests/) + endforeach () + endif () + add_library(go_util SHARED ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/mlpack/capi/arma_util.cpp ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/mlpack/capi/cli_util.cpp) target_link_libraries(go_util mlpack ${MLPACK_LIBRARIES}) target_compile_definitions(go_util PUBLIC "BINDING_TYPE=BINDING_TYPE_GO") set_target_properties(go_util PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/) + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/) # Set the include directories correctly. get_property(GO_INCLUDE_DIRECTORIES DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -164,47 +165,55 @@ if (BUILD_GO_SHLIB) ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") endif() +# Define a global list of models. +define_property(GLOBAL PROPERTY GO_MODELS + BRIEF_DOCS "Global list of models" + FULL_DOCS "Global list of models" +) + +# Initialize list. +set_property(GLOBAL PROPERTY GO_MODELS "") + # Add a macro to build a go binding. macro (add_go_binding name) if (BUILD_GO_BINDINGS) - # Append sources (with directory name) to list of all mlpack sources (used at - # the parent scope). - set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - # Create .h file for C API, e.g. pca.h. - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_h_${name}.cpp - COMMAND ${CMAKE_COMMAND} - -DGENERATE_BINDING_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_h.cpp.in - -DGENERATE_BINDING_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_h_${name}.cpp - -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp - -DPROGRAM_NAME=${name} - -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGoHCPP.cmake - DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_h.cpp.in) + # Include all .h that define model to models.go. + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp" MAIN_FILE) + if (MAIN_FILE MATCHES "PARAM_MODEL") + file(APPEND + "${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/models.go" + "#include \n") + endif() - add_executable(generate_h_${name} - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_h_${name}.cpp - ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/print_h.hpp - ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/print_h.cpp) - target_link_libraries(generate_h_${name} mlpack ${MLPACK_LIBRARIES}) - set_target_properties(generate_h_${name} PROPERTIES COMPILE_FLAGS - -DBINDING_TYPE=BINDING_TYPE_GO) - add_custom_command(TARGET generate_h_${name} POST_BUILD + # Append content to the list. + set_property(GLOBAL APPEND PROPERTY GO_MODELS ${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp) + + # Create ${name}.h. + add_custom_command(OUTPUT + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/capi/${name}.h COMMAND ${CMAKE_COMMAND} - -DGENERATE_BINDING_PROGRAM=${CMAKE_BINARY_DIR}/bin/generate_h_${name} - -DBINDING_OUTPUT_FILE=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/capi/${name}.h - -P ${CMAKE_SOURCE_DIR}/CMake/GenerateGoBinding.cmake) + -DPROGRAM_NAME=${name} + -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp + -DGO_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/go_method.h.in + -DGO_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/capi/${name}.h + -P ${CMAKE_SOURCE_DIR}/CMake/go/ConfigureGoHCPP.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/go_method.h.in + ${CMAKE_SOURCE_DIR}/CMake/go/ConfigureGoHCPP.cmake) # Create .go file, pca.go. add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_go_${name}.cpp COMMAND ${CMAKE_COMMAND} - -DGENERATE_BINDING_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_go.cpp.in - -DGENERATE_BINDING_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_go_${name}.cpp + -DGENERATE_CPP_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_go.cpp.in + -DGENERATE_CPP_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_go_${name}.cpp -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp -DPROGRAM_NAME=${name} - -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGoHCPP.cmake - DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_go.cpp.in) + -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGenerate.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_go.cpp.in + ${CMAKE_SOURCE_DIR}/CMake/ConfigureGenerate.cmake) add_executable(generate_go_${name} + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/capi/${name}.h ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_go_${name}.cpp ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/print_go.hpp ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/print_go.cpp) @@ -214,63 +223,44 @@ if (BUILD_GO_BINDINGS) add_custom_command(TARGET generate_go_${name} POST_BUILD COMMAND ${CMAKE_COMMAND} -DGENERATE_BINDING_PROGRAM=${CMAKE_BINARY_DIR}/bin/generate_go_${name} - -DBINDING_OUTPUT_FILE=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/${name}.go + -DBINDING_OUTPUT_FILE=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/${name}.go -P ${CMAKE_SOURCE_DIR}/CMake/GenerateGoBinding.cmake) - add_dependencies(generate_h_${name} generate_go_${name}) - add_dependencies(go generate_h_${name}) + add_dependencies(go generate_go_${name}) endif () if(BUILD_GO_SHLIB) - # Append sources (with directory name) to list of all mlpack sources (used at - # the parent scope). - set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) - - # Create .cpp file for C API, e.g. pca.cpp. - add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_cpp_${name}.cpp - COMMAND ${CMAKE_COMMAND} - -DGENERATE_BINDING_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_cpp.cpp.in - -DGENERATE_BINDING_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_cpp_${name}.cpp - -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp - -DPROGRAM_NAME=${name} - -P ${CMAKE_SOURCE_DIR}/CMake/ConfigureGoHCPP.cmake - DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/generate_cpp.cpp.in) - - add_executable(generate_cpp_${name} - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/generate_cpp_${name}.cpp - ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/print_cpp.hpp - ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/print_cpp.cpp) - target_link_libraries(generate_cpp_${name} mlpack ${MLPACK_LIBRARIES}) - set_target_properties(generate_cpp_${name} PROPERTIES COMPILE_FLAGS - -DBINDING_TYPE=BINDING_TYPE_GO) - add_custom_command(TARGET generate_cpp_${name} POST_BUILD + # Create ${name}.cpp. + add_custom_command(OUTPUT + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/build/${name}.cpp COMMAND ${CMAKE_COMMAND} - -DGENERATE_BINDING_PROGRAM=${CMAKE_BINARY_DIR}/bin/generate_cpp_${name} - -DBINDING_OUTPUT_FILE=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/capi/${name}.cpp - -P ${CMAKE_SOURCE_DIR}/CMake/GenerateGoBinding.cmake) + -DPROGRAM_NAME=${name} + -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp + -DGO_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/go_method.cpp.in + -DGO_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/build/${name}.cpp + -P ${CMAKE_SOURCE_DIR}/CMake/go/ConfigureGoHCPP.cmake + DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/go/go_method.cpp.in + ${CMAKE_SOURCE_DIR}/CMake/go/ConfigureGoHCPP.cmake) - add_dependencies(generate_cpp_${name} go_copy) - - # Create, e.g., libmlpack_go_pca.so. + # Build libmlpack_go_${name}.so. add_library(mlpack_go_${name} SHARED - ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/capi/${name}.cpp) - set_source_files_properties(${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/capi/${name}.cpp - PROPERTIES GENERATED TRUE) - target_link_libraries(mlpack_go_${name} mlpack ${MLPACK_LIBRARIES}) - target_compile_definitions(mlpack_go_${name} PUBLIC "BINDING_TYPE=BINDING_TYPE_GO") + ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/build/${name}.cpp) + target_link_libraries(mlpack_go_${name} mlpack go_util) set_target_properties(mlpack_go_${name} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/) + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/") + install(TARGETS mlpack_go_${name} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") - add_dependencies(mlpack_go_${name} generate_cpp_${name}) + add_dependencies(mlpack_go_${name} go_copy) add_dependencies(mlpack_go_${name} go_util) add_dependencies(go_shlib mlpack_go_${name}) + if (BUILD_GO_BINDINGS) - add_dependencies(mlpack_go_${name} generate_h_${name}) + add_dependencies(mlpack_go_${name} generate_go_${name}) add_dependencies(go mlpack_go_${name}) endif() endif() diff --git a/src/mlpack/bindings/go/generate_cpp.cpp.in b/src/mlpack/bindings/go/generate_cpp.cpp.in deleted file mode 100644 index 9219d86ea8..0000000000 --- a/src/mlpack/bindings/go/generate_cpp.cpp.in +++ /dev/null @@ -1,49 +0,0 @@ -/* - * @file bindings/go/generate_cpp_${PROGRAM_NAME}.cpp - * @author Yasmine Dumouchel - * - * This is an automatically-generated file that is used to generate the .cpp - * files that are used for the Go bindings. This program will print the - * .cpp file on stdout when run and doesn't need any input parameters. - * - * The CMake variable ${PROGRAM_NAME} must be set for - * this to configure correctly. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#define BINDING_TYPE BINDING_TYPE_GO -// Disable debug output. -#ifdef DEBUG - #define HAD_DEBUG - #undef DEBUG -#endif -#include -#ifdef HAD_DEBUG - #undef HAD_DEBUG - #define DEBUG -#endif - -#include -#include -#include - -// This will include the ParamData options that are a part of the program. -#include <${PROGRAM_MAIN_FILE}> - -using namespace mlpack; -using namespace mlpack::bindings; -using namespace mlpack::bindings::go; -using namespace std; -using namespace mlpack::util; - -int main(int /* argc */, char** /* argv */) -{ - // All the parameters are registered, but stored, so restore them. - // programName is defined in mlpack_main.hpp. - CLI::RestoreSettings(programName); - - PrintCPP(*CLI::GetSingleton().doc, "${PROGRAM_MAIN_FILE}", "${PROGRAM_NAME}"); -} diff --git a/src/mlpack/bindings/go/generate_h.cpp.in b/src/mlpack/bindings/go/generate_h.cpp.in deleted file mode 100644 index ed616bd593..0000000000 --- a/src/mlpack/bindings/go/generate_h.cpp.in +++ /dev/null @@ -1,49 +0,0 @@ -/* - * @file bindings/go/generate_h_${PROGRAM_NAME}.cpp - * @author Yasmine Dumouchel - * - * This is an automatically-generated file that is used to generate the .h - * files that are used for the Go bindings. This program will print the - * .h file on stdout when run and doesn't need any input parameters. - * - * The CMake variable ${PROGRAM_NAME} must be set for - * this to configure correctly. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#define BINDING_TYPE BINDING_TYPE_GO -// Disable debug output. -#ifdef DEBUG - #define HAD_DEBUG - #undef DEBUG -#endif -#include -#ifdef HAD_DEBUG - #undef HAD_DEBUG - #define DEBUG -#endif - -#include -#include -#include - -// This will include the ParamData options that are a part of the program. -#include <${PROGRAM_MAIN_FILE}> - -using namespace mlpack; -using namespace mlpack::bindings; -using namespace mlpack::bindings::go; -using namespace std; -using namespace mlpack::util; - -int main(int /* argc */, char** /* argv */) -{ - // All the parameters are registered, but stored, so restore them. - // programName is defined in mlpack_main.hpp. - CLI::RestoreSettings(programName); - - PrintH(*CLI::GetSingleton().doc, "${PROGRAM_NAME}"); -} diff --git a/src/mlpack/bindings/go/get_printable_type.hpp b/src/mlpack/bindings/go/get_printable_type.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/bindings/go/get_printable_type_impl.hpp b/src/mlpack/bindings/go/get_printable_type_impl.hpp old mode 100755 new mode 100644 diff --git a/src/mlpack/bindings/go/go_method.cpp.in b/src/mlpack/bindings/go/go_method.cpp.in new file mode 100644 index 0000000000..6f3a4f463a --- /dev/null +++ b/src/mlpack/bindings/go/go_method.cpp.in @@ -0,0 +1,24 @@ +/** + * @file build/${PROGRAM_NAME}.cpp + * + * This is an autogenerated file containing implementations of C functions to be + * called by the Go ${PROGRAM_NAME} binding. + */ +#define BINDING_TYPE BINDING_TYPE_GO +#include <${PROGRAM_MAIN_FILE}> +#include + +static void ${GOPROGRAM_NAME}MlpackMain() +{ + mlpackMain(); +} + +extern "C" void mlpack${GOPROGRAM_NAME}() +{ + ${GOPROGRAM_NAME}MlpackMain(); +} + +// Any implementations of methods for dealing with model pointers will be put +// below this comment, if needed. +${MODEL_PTR_IMPLS} + diff --git a/src/mlpack/bindings/go/go_method.h.in b/src/mlpack/bindings/go/go_method.h.in new file mode 100644 index 0000000000..da269eff93 --- /dev/null +++ b/src/mlpack/bindings/go/go_method.h.in @@ -0,0 +1,28 @@ +/** + * @file capi/${PROGRAM_NAME}.h + * + * This is an autogenerated header file for functions specified to the %NAME% + * binding to be called by Go. + */ +#ifndef GO_${PROGRAM_NAME}_H +#define GO_${PROGRAM_NAME}_H + +#include + +#if defined(__cplusplus) || defined(c_plusplus) + +extern "C" +{ +#endif + +extern void mlpack${GOPROGRAM_NAME}(); + +// Any definitions of methods for dealing with model pointers will be put below +// this comment, if needed. +${MODEL_PTR_DEFNS} + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif diff --git a/src/mlpack/bindings/go/go_option.hpp b/src/mlpack/bindings/go/go_option.hpp index fa80bffd8c..fbc14de445 100644 --- a/src/mlpack/bindings/go/go_option.hpp +++ b/src/mlpack/bindings/go/go_option.hpp @@ -20,11 +20,9 @@ #include "print_defn_input.hpp" #include "print_defn_output.hpp" #include "print_doc.hpp" -#include "print_import_decl.hpp" #include "print_input_processing.hpp" #include "print_method_config.hpp" #include "print_method_init.hpp" -#include "print_model_util.hpp" #include "print_output_processing.hpp" namespace mlpack { @@ -103,13 +101,6 @@ class GoOption CLI::GetSingleton().functionMap[data.tname]["DefaultParam"] = &DefaultParam; - - CLI::GetSingleton().functionMap[data.tname]["PrintModelUtilCPP"] = - &PrintModelUtilCPP; - CLI::GetSingleton().functionMap[data.tname]["PrintModelUtilH"] = - &PrintModelUtilH; - CLI::GetSingleton().functionMap[data.tname]["PrintModelUtilGo"] = - &PrintModelUtilGo; CLI::GetSingleton().functionMap[data.tname]["PrintDefnInput"] = &PrintDefnInput; CLI::GetSingleton().functionMap[data.tname]["PrintDefnOutput"] = @@ -121,8 +112,6 @@ class GoOption &PrintMethodConfig; CLI::GetSingleton().functionMap[data.tname]["PrintMethodInit"] = &PrintMethodInit; - CLI::GetSingleton().functionMap[data.tname]["ImportDecl"] = - &ImportDecl; CLI::GetSingleton().functionMap[data.tname]["PrintInputProcessing"] = &PrintInputProcessing; CLI::GetSingleton().functionMap[data.tname]["GetType"] = &GetType; diff --git a/src/mlpack/bindings/go/mlpack/doc.go b/src/mlpack/bindings/go/mlpack/doc.go index 13c8c9ebb7..7523912de7 100644 --- a/src/mlpack/bindings/go/mlpack/doc.go +++ b/src/mlpack/bindings/go/mlpack/doc.go @@ -7,4 +7,4 @@ programs, Go bindings, and C++ classes which can then be integrated into larger-scale machine learning solutions. */ -package mlpack +package mlpack // import "mlpack.org/v1/mlpack" diff --git a/src/mlpack/bindings/go/mlpack/go.mod b/src/mlpack/bindings/go/mlpack/go.mod new file mode 100644 index 0000000000..28d7f43abe --- /dev/null +++ b/src/mlpack/bindings/go/mlpack/go.mod @@ -0,0 +1,5 @@ +module mlpack.org/v1/mlpack + +go 1.13 + +require gonum.org/v1/gonum v0.7.0 diff --git a/src/mlpack/bindings/go/mlpack/go.sum b/src/mlpack/bindings/go/mlpack/go.sum new file mode 100644 index 0000000000..0ee9003565 --- /dev/null +++ b/src/mlpack/bindings/go/mlpack/go.sum @@ -0,0 +1,18 @@ +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2 h1:y102fOLFqhV41b+4GPiJoa0k/x+pJcEi2/HB1Y5T6fU= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.7.0 h1:Hdks0L0hgznZLG9nzXb8vZ0rRvqNvAcgAp84y7Mwkgw= +gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/src/mlpack/bindings/go/print_cpp.cpp b/src/mlpack/bindings/go/print_cpp.cpp deleted file mode 100644 index fc69c9ea84..0000000000 --- a/src/mlpack/bindings/go/print_cpp.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @file bindings/go/print_cpp.cpp - * @author Yasmine Dumouchel - * - * Implementation of function to generate a .cpp file given a list of parameters - * for the function. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#include "print_cpp.hpp" -#include "camel_case.hpp" -#include -#include -#include - -using namespace mlpack::util; -using namespace std; - -namespace mlpack { -namespace bindings { -namespace go { - -/** - * Given a list of parameter definition and program documentation, print a - * generated .cpp file to stdout. - */ -void PrintCPP(const ProgramDoc& programInfo, - const string& mainFilename, - const string& functionName) -{ - // Restore parameters. - CLI::RestoreSettings(programInfo.programName); - - const std::map& parameters = CLI::Parameters(); - typedef std::map::const_iterator ParamIter; - - // First, we must generate the header comment and namespace. - cout << "#include <" << mainFilename << ">" << endl; - cout << "#include " << endl; - cout << endl; - cout << "using namespace mlpack;" << endl; - cout << "using namespace mlpack::util;" << endl; - cout << "using namespace std;" << endl; - cout << endl; - - // Then we must print utility function for model type parameters if needed. - for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) - { - const util::ParamData& d = it->second; - if (d.input) - CLI::GetSingleton().functionMap[d.tname]["PrintModelUtilCPP"](d, - NULL, NULL); - } - - // Finally, we generate the wrapper function for mlpackMain(). - std::string goFunctionName = CamelCase(functionName, false); - cout << "static void " << goFunctionName << "MlpackMain()" << endl; - cout << "{" << endl; - cout << " " << "mlpackMain();" << endl; - cout << "}" << endl; - cout << endl; - cout << "extern \"C\" void mlpack" << goFunctionName << "()" << endl; - cout << "{" << endl; - cout << " " << goFunctionName << "MlpackMain();" << endl; - cout << "}" << endl; - cout << endl; -} - -} // namespace go -} // namespace bindings -} // namespace mlpack diff --git a/src/mlpack/bindings/go/print_cpp.hpp b/src/mlpack/bindings/go/print_cpp.hpp deleted file mode 100644 index bd0cd3bcfb..0000000000 --- a/src/mlpack/bindings/go/print_cpp.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file bindings/go/print_cpp.hpp - * @author Yasmine Dumouchel - * - * Given a list of ParamData structures, emit a .cpp file defining the - * Go bindings. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#ifndef MLPACK_BINDINGS_GO_PRINT_CPP_HPP -#define MLPACK_BINDINGS_GO_PRINT_CPP_HPP - -#include - -namespace mlpack { -namespace bindings { -namespace go { - -/** - * Given a list of parameter definition and program documentation, print a - * generated .cpp file to stdout. - */ -void PrintCPP(const util::ProgramDoc& programInfo, - const std::string& mainFilename, - const std::string& functionName); - - -} // namespace go -} // namespace bindings -} // namespace mlpack - -#endif diff --git a/src/mlpack/bindings/go/print_go.cpp b/src/mlpack/bindings/go/print_go.cpp index f12a3596a9..2b9a3f4732 100644 --- a/src/mlpack/bindings/go/print_go.cpp +++ b/src/mlpack/bindings/go/print_go.cpp @@ -81,16 +81,15 @@ void PrintGo(const util::ProgramDoc& programInfo, cout << endl; // Then we must print the import of the gonum package. - cout << "import (" << endl; - cout << " " << "\"gonum.org/v1/gonum/mat\" " << endl; - for (size_t i = 0; i < inputOptions.size(); ++i) + for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) { - const util::ParamData& d = parameters.at(inputOptions[i]); - size_t indent = 2; - CLI::GetSingleton().functionMap[d.tname]["ImportDecl"](d, - (void*) &indent, NULL); + const util::ParamData& d = it->second; + if ((d.cppType).compare(0, 6, "arma::") == 0) + { + std::cout << "import \"gonum.org/v1/gonum/mat\" " << std::endl; + break; + } } - cout << ")" << endl; cout << endl; std::string goFunctionName = CamelCase(functionName, false); @@ -123,15 +122,6 @@ void PrintGo(const util::ProgramDoc& programInfo, cout << "}" << endl; cout << endl; - // Then we must print utility function for model type parameters if needed. - for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) - { - const util::ParamData& d = it->second; - if (d.input) - CLI::GetSingleton().functionMap[d.tname]["PrintModelUtilGo"](d, - NULL, NULL); - } - // Print the comment describing the function and its parameters. cout << "/*" << endl; cout << " " << HyphenateString(programInfo.documentation(), 2) << endl; diff --git a/src/mlpack/bindings/go/print_h.cpp b/src/mlpack/bindings/go/print_h.cpp deleted file mode 100644 index 087af1019d..0000000000 --- a/src/mlpack/bindings/go/print_h.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file bindings/go/print_h.cpp - * @author Yasmine Dumouchel - * - * Implementation of function to generate a .h file given a list of parameters - * for the function. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#include "print_h.hpp" -#include "camel_case.hpp" -#include -#include -#include - -using namespace mlpack::util; -using namespace std; - -namespace mlpack { -namespace bindings { -namespace go { - -/** - * Given a list of parameter definition and program documentation, print a - * generated .h file to stdout. - * - * @param programInfo Documentation for the program. - * @param functionName Name of the function (i.e. "pca"). - */ -void PrintH(const util::ProgramDoc& programInfo, - const std::string& functionName) -{ - // Restore parameters. - CLI::RestoreSettings(programInfo.programName); - - const std::map& parameters = CLI::Parameters(); - typedef std::map::const_iterator ParamIter; - - // First, we must generate the header comment and namespace. - cout << "#include " << endl; - cout << "#include " << endl; - cout << endl; - cout << "#if defined(__cplusplus) || defined(c_plusplus)" << endl; - cout << "extern \"C\" {" << endl; - cout << "#endif" << endl; - cout << endl; - - // Then we must print utility function for model type parameters if needed. - for (ParamIter it = parameters.begin(); it != parameters.end(); ++it) - { - const util::ParamData& d = it->second; - if (d.input) - CLI::GetSingleton().functionMap[d.tname]["PrintModelUtilH"](d, - NULL, NULL); - } - - std::string goFunctionName = CamelCase(functionName, false); - // We generate the wrapper function for mlpackMain(). - cout << "extern void mlpack" << goFunctionName << "();" << endl; - cout << endl; - - // Finally we close print the closing bracket for extern C. - cout << "#if defined(__cplusplus) || defined(c_plusplus)" << endl; - cout << "}" << endl; - cout << "#endif" << endl; -} - -} // namespace go -} // namespace bindings -} // namespace mlpack diff --git a/src/mlpack/bindings/go/print_h.hpp b/src/mlpack/bindings/go/print_h.hpp deleted file mode 100644 index ea773e3878..0000000000 --- a/src/mlpack/bindings/go/print_h.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @file bindings/go/print_h.hpp - * @author Yasmine Dumouchel - * - * Given a list of ParamData structures, emit a .h file defining the - * Go bindings. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#ifndef MLPACK_BINDINGS_GO_PRINT_H_HPP -#define MLPACK_BINDINGS_GO_PRINT_H_HPP - -#include - -namespace mlpack { -namespace bindings { -namespace go { - -/** - * Given a list of parameter definition and program documentation, print a - * generated .h file to stdout. - * - * @param programInfo Documentation for the program. - * @param functionName Name of the function (i.e. "pca"). - */ -void PrintH(const util::ProgramDoc& programInfo, - const std::string& functionName); - - -} // namespace go -} // namespace bindings -} // namespace mlpack - -#endif diff --git a/src/mlpack/bindings/go/print_import_decl.hpp b/src/mlpack/bindings/go/print_import_decl.hpp deleted file mode 100644 index 8147993024..0000000000 --- a/src/mlpack/bindings/go/print_import_decl.hpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file bindings/go/print_import_decl.hpp - * @author Yasmine Dumouchel - * - * Print the necessary imports for go bindings. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#ifndef MLPACK_BINDINGS_GO_IMPORT_DECL_HPP -#define MLPACK_BINDINGS_GO_IMPORT_DECL_HPP - -#include - -namespace mlpack { -namespace bindings { -namespace go { - -/** - * For a serializable type, print a cppclass definition. - */ -template -void ImportDecl( - const util::ParamData& /* d */, - const size_t indent, - const typename boost::disable_if>::type* = 0, - const typename boost::enable_if>::type* = 0) -{ - /** - * This will give output of the form: - */ - const std::string prefix = std::string(indent, ' '); - // Now import all the necessary packages. - std::cout << prefix << "\"runtime\" " << std::endl; - std::cout << prefix << "\"unsafe\" " << std::endl; -} - -/** - * For a non-serializable type, print nothing. - */ -template -void ImportDecl( - const util::ParamData& /* d */, - const size_t /* indent */, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>::type* = 0) -{ - // Print nothing. -} - -/** - * For a matrix type, print nothing. - */ -template -void ImportDecl( - const util::ParamData& /* d */, - const size_t /* indent */, - const typename boost::enable_if>::type* = 0) -{ - // Print nothing. -} - -/** - * Print the cppclass definition for a serializable model; print nothing for a - * non-serializable type. - * - * @param d Parameter info struct. - * @param indent Pointer to size_t indicating indent. - * @param * (output) Unused parameter. - */ -template -void ImportDecl(const util::ParamData& d, - const void* indent, - void* /* output */) -{ - ImportDecl::type>(d, *((size_t*) indent)); -} - -} // namespace go -} // namespace bindings -} // namespace mlpack - -#endif diff --git a/src/mlpack/bindings/go/print_input_processing.hpp b/src/mlpack/bindings/go/print_input_processing.hpp index 4c7df3aa41..505e64c869 100644 --- a/src/mlpack/bindings/go/print_input_processing.hpp +++ b/src/mlpack/bindings/go/print_input_processing.hpp @@ -296,8 +296,8 @@ void PrintInputProcessing( { goParamName = CamelCase(goParamName, true); // Print function call to set the given parameter into the cli. - std::cout << prefix << "set" << strippedType << "(\"" << goParamName - << "\", " << paramName << ")" << std::endl; + std::cout << prefix << "set" << strippedType << "(\"" << d.name + << "\", " << goParamName << ")" << std::endl; // Print function call to set the given parameter as passed. std::cout << prefix << "setPassed(\"" << d.name << "\")" << std::endl; diff --git a/src/mlpack/bindings/go/print_model_util.hpp b/src/mlpack/bindings/go/print_model_util.hpp deleted file mode 100644 index 7426effb31..0000000000 --- a/src/mlpack/bindings/go/print_model_util.hpp +++ /dev/null @@ -1,349 +0,0 @@ -/** - * @file bindings/go/print_model_util.hpp - * @author Yasmine Dumouchel - * - * Print the functions and structs associated with serializable model. - * for generating the .cpp, .h, and .go binding. - * - * mlpack is free software; you may redistribute it and/or modify it under the - * terms of the 3-clause BSD license. You should have received a copy of the - * 3-clause BSD license along with mlpack. If not, see - * http://www.opensource.org/licenses/BSD-3-Clause for more information. - */ -#ifndef MLPACK_BINDINGS_GO_PRINT_CLASS_DEFN_HPP -#define MLPACK_BINDINGS_GO_PRINT_CLASS_DEFN_HPP - -#include "strip_type.hpp" - -namespace mlpack { -namespace bindings { -namespace go { - -/** - * Non-serializable models don't require any special definitions, so this prints - * nothing. - */ -template -void PrintModelUtilCPP( - const util::ParamData& /* d */, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>>::type* = 0) -{ - // Do nothing. -} - -/** - * Matrices don't require any special definitions, so this prints nothing. - */ -template -void PrintModelUtilCPP( - const util::ParamData& /* d */, - const typename boost::enable_if>::type* = 0) -{ - // Do nothing. -} - -/** - * Matrices with Info don't require any special definitions, so this prints nothing. - */ -template -void PrintModelUtilCPP( - const util::ParamData& /* d */, - const typename boost::enable_if>>::type* = 0) -{ - // Do nothing. -} - -/** - * Serializable models require a special class definition. - */ -template -void PrintModelUtilCPP( - const util::ParamData& d, - const typename boost::disable_if>::type* = 0, - const typename boost::enable_if>::type* = 0) -{ - // First, we have to parse the type. If we have something like, e.g., - // 'LogisticRegression<>', we must convert this to 'LogisticRegression[].' - std::string goStrippedType, strippedType, printedType, defaultsType; - StripType(d.cppType, goStrippedType, strippedType, printedType, defaultsType); - /** - * This gives us code like: - * - * extern "C" void mlpackSet\Ptr( - * const char* identifier, - * void *value) - * { - * SetParamPtr\(identifier, - * static_cast\*(value)); - * } - * - */ - std::cout << "extern \"C\" void mlpackSet" << strippedType - << "Ptr(" << std::endl; - std::cout << " const char* identifier, " << std::endl; - std::cout << " void* value)" << std::endl; - std::cout << "{" << std::endl; - std::cout << " SetParamPtr<" << printedType - << ">(identifier," << std::endl; - std::cout << " static_cast<" << printedType - << "*>(value));" << std::endl; - std::cout << "}" << std::endl; - std::cout << std::endl; - - /** - * This gives us code like: - * - * extern "C" void *mlpackGet\Ptr(const char* identifier) - * { - * \ *modelptr = GetParamPtr\(identifier); - * return modelptr; - * } - * - */ - std::cout << "extern \"C\" void *mlpackGet" << strippedType - << "Ptr(const char* identifier)" << std::endl; - std::cout << "{" << std::endl; - std::cout << " " << printedType << " *modelptr = GetParamPtr<" - << printedType << ">(identifier);" << std::endl; - std::cout << " return modelptr;" << std::endl; - std::cout << "}" << std::endl; - std::cout << std::endl; -} - -/** - * Print the function to set and get serialization models from Go to mlpack. - * - * @param d Parameter data. - * @param * (input) Unused parameter. - * @param * (output) Unused parameter. - */ -template -void PrintModelUtilCPP(const util::ParamData& d, - const void* /* input */, - void* /* output */) -{ - PrintModelUtilCPP::type>(d); -} - - -/** - * Non-serializable models don't require any special definitions, so this prints - * nothing. - */ -template -void PrintModelUtilH( - const util::ParamData& /* d */, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>>::type* = 0) - -{ - // Do nothing. -} - -/** - * Matrices don't require any special definitions, so this prints nothing. - */ -template -void PrintModelUtilH( - const util::ParamData& /* d */, - const typename boost::enable_if>::type* = 0) -{ - // Do nothing. -} - -/** - * Matrices with Info don't require any special definitions, so this prints nothing. - */ -template -void PrintModelUtilH( - const util::ParamData& /* d */, - const typename boost::enable_if>>::type* = 0) -{ - // Do nothing. -} - -/** - * Serializable models require a special class definition. - */ -template -void PrintModelUtilH( - const util::ParamData& d, - const typename boost::disable_if>::type* = 0, - const typename boost::enable_if>::type* = 0) -{ - // First, we have to parse the type. If we have something like, e.g., - // 'LogisticRegression<>', we must convert this to 'LogisticRegression[].' - std::string goStrippedType, strippedType, printedType, defaultsType; - StripType(d.cppType, goStrippedType, strippedType, printedType, defaultsType); - - /** - * This gives us code like: - * - * extern void *mlpackSet\Ptr(const char* identifier, void* value); - * - */ - std::cout << "extern void mlpackSet" << strippedType - << "Ptr(const char* identifier, void* value);" << std::endl; - std::cout << std::endl; - - /** - * This gives us code like: - * - * extern void *mlpackGet\Ptr(const char* identifier); - * - */ - std::cout << "extern void *mlpackGet" << strippedType - << "Ptr(const char* identifier);" << std::endl; - std::cout << std::endl; -} - -/** - * Print the function to set and get serialization models from Go to mlpack. - * - * @param d Parameter data. - * @param * (input) Unused parameter. - * @param * (output) Unused parameter. - */ -template -void PrintModelUtilH(const util::ParamData& d, - const void* /* input */, - void* /* output */) -{ - PrintModelUtilH::type>(d); -} - -/** - * Non-serializable models don't require any special definitions, so this prints - * nothing. - */ -template -void PrintModelUtilGo( - const util::ParamData& /* d */, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>::type* = 0, - const typename boost::disable_if>>::type* = 0) -{ - // Do nothing. -} - -/** - * Matrices don't require any special definitions, so this prints nothing. - */ -template -void PrintModelUtilGo( - const util::ParamData& /* d */, - const typename boost::enable_if>::type* = 0) -{ - // Do nothing. -} - -/** - * Matrices with Info don't require any special definitions, so this prints nothing. - */ -template -void PrintModelUtilGo( - const util::ParamData& /* d */, - const typename boost::enable_if>>::type* = 0) -{ - // Do nothing. -} - -/** - * Serializable models require a special class definition. - */ -template -void PrintModelUtilGo( - const util::ParamData& d, - const typename boost::disable_if>::type* = 0, - const typename boost::enable_if>::type* = 0) -{ - // First, we have to parse the type. If we have something like, e.g., - // 'LogisticRegression<>', we must convert this to 'LogisticRegression[].' - std::string goStrippedType, strippedType, printedType, defaultsType; - StripType(d.cppType, goStrippedType, strippedType, printedType, defaultsType); - - /** - * This gives us code like: - * - * type \ struct { - * mem unsafe.Pointer - * } - * - */ - std::cout << "type " << goStrippedType << " struct {" << std::endl; - std::cout << " mem unsafe.Pointer" << std::endl; - std::cout << "}" << std::endl; - std::cout << std::endl; - - /** - * This gives us code like: - * - * func (m *\) alloc\(identifier string) { - * m.mem = C.mlpackGet\Ptr(C.CString(identifier)) - * runtime.KeepAlive(m) - * } - * - */ - std::cout << "func (m *" << goStrippedType << ") alloc" - << strippedType << "(identifier string) {" << std::endl; - std::cout << " m.mem = C.mlpackGet" << strippedType - << "Ptr(C.CString(identifier))" << std::endl; - std::cout << " runtime.KeepAlive(m)" << std::endl; - std::cout << "}" << std::endl; - std::cout << std::endl; - - /** - * This gives us code like: - * - * func (m *\) get\(identifier string) { - * m.alloc\(identifier) - * } - * - */ - std::cout << "func (m *" << goStrippedType << ") get" - << strippedType << "(identifier string) {" << std::endl; - std::cout << " m.alloc" << strippedType << "(identifier)" << std::endl; - std::cout << "}" << std::endl; - std::cout << std::endl; - - // Print function to set specified mlpack parameter object ptr from Go. - std::cout << "func set" << strippedType - << "(identifier string, ptr *" << goStrippedType << ") {" - << std::endl; - std::cout << " C.mlpackSet" << strippedType - << "Ptr(C.CString(identifier), (unsafe.Pointer)(ptr.mem))" - << std::endl; - std::cout << "}" << std::endl; - std::cout << std::endl; -} - -/** - * Print the Go struct for Go serialization model and their associated - * set and get methods. - * - * @param d Parameter data. - * @param * (input) Unused parameter. - * @param * (output) Unused parameter. - */ -template -void PrintModelUtilGo(const util::ParamData& d, - const void* /* input */, - void* /* output */) -{ - PrintModelUtilGo::type>(d); -} - -} // namespace go -} // namespace bindings -} // namespace mlpack - -#endif diff --git a/src/mlpack/bindings/go/tests/CMakeLists.txt b/src/mlpack/bindings/go/tests/CMakeLists.txt index bb041883d1..b4a1b754dc 100644 --- a/src/mlpack/bindings/go/tests/CMakeLists.txt +++ b/src/mlpack/bindings/go/tests/CMakeLists.txt @@ -4,7 +4,8 @@ add_go_binding(test_go_binding) if (BUILD_GO_BINDINGS) add_test(NAME go_binding_test COMMAND go test -v ${CMAKE_CURRENT_SOURCE_DIR}/go_binding_test.go - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/) + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/) set_tests_properties(go_binding_test - PROPERTIES ENVIRONMENT "GOPATH=$ENV{GOPATH}:${CMAKE_BINARY_DIR};LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}:${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/mlpack/") + PROPERTIES ENVIRONMENT "GOPATH=$ENV{GOPATH}:${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/; + LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}:${CMAKE_BINARY_DIR}/src/mlpack/bindings/go/src/mlpack.org/v1/mlpack/") endif() diff --git a/src/mlpack/bindings/go/tests/go_binding_test.go b/src/mlpack/bindings/go/tests/go_binding_test.go index bc90a11e85..846e29bede 100644 --- a/src/mlpack/bindings/go/tests/go_binding_test.go +++ b/src/mlpack/bindings/go/tests/go_binding_test.go @@ -1,7 +1,7 @@ package main import ( - "mlpack/bindings/go/mlpack" + "mlpack.org/v1/mlpack" "testing" "os" diff --git a/src/mlpack/bindings/julia/CMakeLists.txt b/src/mlpack/bindings/julia/CMakeLists.txt index 7a2fcb7304..275faafe68 100644 --- a/src/mlpack/bindings/julia/CMakeLists.txt +++ b/src/mlpack/bindings/julia/CMakeLists.txt @@ -21,7 +21,7 @@ if (BUILD_JULIA_BINDINGS) find_package(Julia 0.7.0) if (NOT JULIA_FOUND) unset(BUILD_JULIA_BINDINGS CACHE) - message(FATAL_ERROR "Could not Build Julia Bindings") + message(FATAL_ERROR "Julia not found; cannot build Julia bindings!") endif() else () find_package(Julia 0.7.0) @@ -148,12 +148,12 @@ if (BUILD_JULIA_BINDINGS) ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.h ${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.cpp COMMAND ${CMAKE_COMMAND} - -DPROGRAM_NAME="${name}" - -DPROGRAM_MAIN_FILE="${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp" - -DJULIA_H_IN="${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.h.in" - -DJULIA_H_OUT="${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.h" - -DJULIA_CPP_IN="${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.cpp.in" - -DJULIA_CPP_OUT="${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.cpp" + -DPROGRAM_NAME=${name} + -DPROGRAM_MAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/${name}_main.cpp + -DJULIA_H_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.h.in + -DJULIA_H_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.h + -DJULIA_CPP_IN=${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.cpp.in + -DJULIA_CPP_OUT=${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/julia_${name}.cpp -P ${CMAKE_SOURCE_DIR}/CMake/julia/ConfigureJuliaHCPP.cmake DEPENDS ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.h.in ${CMAKE_SOURCE_DIR}/src/mlpack/bindings/julia/julia_method.cpp.in @@ -218,7 +218,7 @@ if (BUILD_JULIA_BINDINGS) RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/bin/") add_custom_command(TARGET generate_jl_${name} POST_BUILD COMMAND ${CMAKE_COMMAND} - -DGENERATE_BINDING_PROGRAM="${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/bin/generate_jl_${name}" + -DGENERATE_BINDING_PROGRAM=${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/build/bin/generate_jl_${name} -DBINDING_OUTPUT_FILE=${CMAKE_BINARY_DIR}/src/mlpack/bindings/julia/mlpack/src/${name}.jl -P ${CMAKE_SOURCE_DIR}/CMake/GenerateBinding.cmake) diff --git a/src/mlpack/core/cv/metrics/facilities.hpp b/src/mlpack/core/cv/metrics/facilities.hpp index a9bd903113..c7b9b4b70e 100644 --- a/src/mlpack/core/cv/metrics/facilities.hpp +++ b/src/mlpack/core/cv/metrics/facilities.hpp @@ -1,6 +1,7 @@ /** * @file core/cv/metrics/facilities.hpp * @author Kirill Mishchenko + * @author Khizir Siddiqui * * Functionality that is used more than in one metric. * @@ -13,6 +14,7 @@ #define MLPACK_CORE_CV_METRICS_FACILITIES_HPP #include +#include namespace mlpack { namespace cv { @@ -40,6 +42,29 @@ void AssertSizes(const DataType& data, } } +/** + * Pairwise distance of the given data. + * + * @param data Column-major matrix. + * @param metric Distance metric to be used. + */ +template +DataType PairwiseDistances(const DataType& data, + const Metric& metric) +{ + DataType distances = DataType(data.n_cols, data.n_cols, arma::fill::none); + for (size_t i = 0; i < data.n_cols; i++) + { + for (size_t j = 0; j < i; j++) + { + distances(i, j) = metric.Evaluate(data.col(i), data.col(j)); + distances(j, i) = distances(i, j); + } + } + distances.diag().zeros(); + return distances; +} + } // namespace cv } // namespace mlpack diff --git a/src/mlpack/core/cv/metrics/silhouette_score.hpp b/src/mlpack/core/cv/metrics/silhouette_score.hpp new file mode 100644 index 0000000000..a327e48daf --- /dev/null +++ b/src/mlpack/core/cv/metrics/silhouette_score.hpp @@ -0,0 +1,108 @@ +/** + * @file silhouette_score.hpp + * @author Khizir Siddiqui + * + * The Silhouette metric. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef MLPACK_CORE_CV_METRICS_SILHOUETTE_SCORE_HPP +#define MLPACK_CORE_CV_METRICS_SILHOUETTE_SCORE_HPP + +#include + +namespace mlpack { +namespace cv { + +/** + * The Silhouette Score is a metric of performance for clustering + * that represents the quality of clusters made as a result. + * It provides an indication of goodness of fit and therefore a measure of how + * well unseen samples are likely to be predicted by the model, considering + * the inter-cluster and intra-cluster dissimilarities. + * Silhoutte Score is dependent on the metric used to calculate the + * dissimilarities. The best possible score is @f$ s(i) = 1.0 @f$. + * Smaller values of Silhouette Score indicate poor clustering. + * Negative values would occur when a wrong label was put on the element. + * Values near zero indicate overlapping clusters. + * For an element i @f$ a(i) @f$ is within cluster average dissimilarity + * and @f$ b(i) @f$ is minimum of average dissimilarity from other clusters. + * the Silhouette Score @f$ s(i) @f$ of a Sample is calculated by + * @f{eqnarray*}{ + * s(i) &=& \frac{b(i) - a(i)}{max\{b(i), a(i)\}} + * @f} + * + * The Overall Silhouette Score is the mean of individual silhoutte scores. + */ +class SilhouetteScore +{ + public: + /** + * Find the overall silhouette score. + * + * @param X Column-major data used for clustering. + * @param labels Labels assigned to data by clustering. + * @param metric Metric to be used to calculate dissimilarity. + * @return (double) silhouette score. + */ + template + static double Overall(const DataType& X, + const arma::Row& labels, + const Metric& metric); + + /** + * Find the individual silhouette scores for precomputted dissimilarites. + * + * @param distances Square matrix containing distances between data points. + * @param labels Labels assigned to data by clustering. + * @return (arma::rowvec) element-wise silhouette score. + */ + template + static arma::rowvec SamplesScore(const DataType& distances, + const arma::Row& labels); + + /** + * Find silhouette score of all individual elements. + * (Distance not precomputed). + * + * @param X Column-major data used for clustering. + * @param labels Labels assigned to data by clustering. + * @param metric Metric to be used to calculate dissimilarity. + * @return (arma::rowvec) element-wise silhouette score. + */ + template + static arma::rowvec SamplesScore(const DataType& X, + const arma::Row& labels, + const Metric& metric); + + /** + * Find mean distance of element from a given cluster. + * + * @param distances colvec containing distances from other elements. + * @param labels Labels assigned to data by clustering. + * @param label label of the target cluster. + * @param sameCluster true if calculating mean distance from same cluster. + * @return (double) distance from the cluster. + */ + static double MeanDistanceFromCluster(const arma::colvec& distances, + const arma::Row& labels, + const size_t& label, + const bool& sameCluster = false); + + /** + * Information for hyper-parameter tuning code. It indicates that we want + * to maximize the metric. + */ + static const bool NeedsMinimization = false; +}; + +} // namespace cv +} // namespace mlpack + +// Include implementation. +#include "silhouette_score_impl.hpp" + +#endif diff --git a/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp b/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp new file mode 100644 index 0000000000..89041f736e --- /dev/null +++ b/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp @@ -0,0 +1,108 @@ +/** + * @file silhouette_score_impl.hpp + * @author Khizir Siddiqui + * + * The implementation of the class SilhouetteScore. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef MLPACK_CORE_CV_METRICS_SILHOUETTE_SCORE_IMPL_HPP +#define MLPACK_CORE_CV_METRICS_SILHOUETTE_SCORE_IMPL_HPP + +#include + +namespace mlpack { +namespace cv { + +template +double SilhouetteScore::Overall(const DataType& X, + const arma::Row& labels, + const Metric& metric) +{ + AssertSizes(X, labels, "SilhouetteScore::Overall()"); + return arma::mean(SamplesScore(X, labels, metric)); +} + +template +arma::rowvec SilhouetteScore::SamplesScore(const DataType& distances, + const arma::Row& labels) +{ + AssertSizes(distances, labels, "SilhouetteScore::SamplesScore()"); + + // Stores the silhouette scores of individual samples. + arma::rowvec sampleScores(distances.n_rows); + // Finds one index per cluster. + arma::ucolvec clusterLabels = arma::find_unique(labels, false); + + for (size_t i = 0; i < distances.n_rows; i++) + { + double interClusterDistance = DBL_MAX, intraClusterDistance = 0; + double minInterClusterDistance = DBL_MAX; + for (size_t j = 0; j < clusterLabels.n_elem; j++) + { + size_t clusterLabel = labels(clusterLabels(j)); + if (labels(i) != clusterLabel) { + interClusterDistance = MeanDistanceFromCluster( + distances.col(i), labels, clusterLabel, false); + if (interClusterDistance < minInterClusterDistance) { + minInterClusterDistance = interClusterDistance; + } + } else { + intraClusterDistance = MeanDistanceFromCluster( + distances.col(i), labels, clusterLabel, true); + if (intraClusterDistance == 0) { + // s(i) = 0, no more calculation needed. + break; + } + } + } + if (intraClusterDistance == 0) { + // i is the only element in the cluster. + sampleScores(i) = 0.0; + } else { + sampleScores(i) = minInterClusterDistance - intraClusterDistance; + sampleScores(i) /= std::max( + intraClusterDistance, minInterClusterDistance); + } + } + return sampleScores; +} + +template +arma::rowvec SilhouetteScore::SamplesScore(const DataType& X, + const arma::Row& labels, + const Metric& metric) +{ + AssertSizes(X, labels, "SilhouetteScore::SamplesScore()"); + DataType distances = PairwiseDistances(X, metric); + return SamplesScore(distances, labels); +} + +double SilhouetteScore::MeanDistanceFromCluster(const arma::colvec& distances, + const arma::Row& labels, + const size_t& elemLabel, + const bool& sameCluster) +{ + // Find indices of elements with same label as elemLabel. + arma::uvec sameClusterIndices = arma::find(labels == elemLabel); + + // Numver of elements in the given cluster. + size_t numSameCluster = sameClusterIndices.n_elem; + if ((sameCluster == true) && (numSameCluster == 1)) + { + // Return 0 if subject element is the only element in cluster. + return 0.0; + } else { + double distance = arma::accu(distances.elem(sameClusterIndices)); + distance /= (numSameCluster - sameCluster); + return distance; + } +} + +} // namespace cv +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/gmm/CMakeLists.txt b/src/mlpack/methods/gmm/CMakeLists.txt index 417d40fc11..3e9b981a04 100644 --- a/src/mlpack/methods/gmm/CMakeLists.txt +++ b/src/mlpack/methods/gmm/CMakeLists.txt @@ -33,11 +33,11 @@ add_markdown_docs(gmm_train "cli;python;julia;go" "clustering") add_cli_executable(gmm_generate) add_python_binding(gmm_generate) add_julia_binding(gmm_generate) -#add_go_binding(gmm_generate) -add_markdown_docs(gmm_generate "cli;python;julia" "clustering") +add_go_binding(gmm_generate) +add_markdown_docs(gmm_generate "cli;python;julia;go" "clustering") add_cli_executable(gmm_probability) add_python_binding(gmm_probability) add_julia_binding(gmm_probability) -#add_go_binding(gmm_probability) -add_markdown_docs(gmm_probability "cli;python;julia" "clustering") +add_go_binding(gmm_probability) +add_markdown_docs(gmm_probability "cli;python;julia;go" "clustering") diff --git a/src/mlpack/methods/hmm/CMakeLists.txt b/src/mlpack/methods/hmm/CMakeLists.txt index e3712427c7..790c0b64c2 100644 --- a/src/mlpack/methods/hmm/CMakeLists.txt +++ b/src/mlpack/methods/hmm/CMakeLists.txt @@ -22,23 +22,23 @@ set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) add_cli_executable(hmm_train) add_python_binding(hmm_train) add_julia_binding(hmm_train) -#add_go_binding(hmm_train) -add_markdown_docs(hmm_train "cli;python;julia" "misc. / other") +add_go_binding(hmm_train) +add_markdown_docs(hmm_train "cli;python;julia;go" "misc. / other") add_cli_executable(hmm_loglik) add_python_binding(hmm_loglik) add_julia_binding(hmm_loglik) -#add_go_binding(hmm_loglik) -add_markdown_docs(hmm_loglik "cli;python;julia" "misc. / other") +add_go_binding(hmm_loglik) +add_markdown_docs(hmm_loglik "cli;python;julia;go" "misc. / other") add_cli_executable(hmm_viterbi) add_python_binding(hmm_viterbi) add_julia_binding(hmm_viterbi) -#add_go_binding(hmm_viterbi) -add_markdown_docs(hmm_viterbi "cli;python;julia" "misc. / other") +add_go_binding(hmm_viterbi) +add_markdown_docs(hmm_viterbi "cli;python;julia;go" "misc. / other") add_cli_executable(hmm_generate) add_python_binding(hmm_generate) add_julia_binding(hmm_generate) -#add_go_binding(hmm_generate) -add_markdown_docs(hmm_generate "cli;python;julia" "misc. / other") +add_go_binding(hmm_generate) +add_markdown_docs(hmm_generate "cli;python;julia;go" "misc. / other") diff --git a/src/mlpack/methods/kde/CMakeLists.txt b/src/mlpack/methods/kde/CMakeLists.txt index cd7442fbdf..177df28981 100644 --- a/src/mlpack/methods/kde/CMakeLists.txt +++ b/src/mlpack/methods/kde/CMakeLists.txt @@ -21,4 +21,6 @@ set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) add_cli_executable(kde) add_python_binding(kde) -add_markdown_docs(kde "cli;python" "misc. / other") +add_julia_binding(kde) +add_go_binding(kde) +add_markdown_docs(kde "cli;python;julia;go" "misc. / other") diff --git a/src/mlpack/methods/kde/kde_main.cpp b/src/mlpack/methods/kde/kde_main.cpp index a8eb67022a..155146b41b 100644 --- a/src/mlpack/methods/kde/kde_main.cpp +++ b/src/mlpack/methods/kde/kde_main.cpp @@ -9,8 +9,10 @@ * 3-clause BSD license along with mlpack. If not, see * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ - +#include +#include #include +#include #include "kde.hpp" #include "kde_model.hpp" diff --git a/src/mlpack/methods/nmf/CMakeLists.txt b/src/mlpack/methods/nmf/CMakeLists.txt index f48cea62fe..75fd58e80b 100644 --- a/src/mlpack/methods/nmf/CMakeLists.txt +++ b/src/mlpack/methods/nmf/CMakeLists.txt @@ -2,4 +2,4 @@ add_cli_executable(nmf) add_python_binding(nmf) add_julia_binding(nmf) add_go_binding(nmf) -add_markdown_docs(nmf "cli;python;julia" "misc. / other") +add_markdown_docs(nmf "cli;python;julia;go" "misc. / other") diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 77e4fcc2e4..e969a43714 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable(mlpack_test drusilla_select_test.cpp emst_test.cpp fastmks_test.cpp + facilities_test.cpp feedforward_network_test.cpp gan_test.cpp gmm_test.cpp diff --git a/src/mlpack/tests/cv_test.cpp b/src/mlpack/tests/cv_test.cpp index bc7e2291ab..1407a6102e 100644 --- a/src/mlpack/tests/cv_test.cpp +++ b/src/mlpack/tests/cv_test.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -719,4 +720,19 @@ BOOST_AUTO_TEST_CASE(KFoldCVWithDTTestUnevenBinsWeighted) BOOST_REQUIRE_GT(accuracy, 0.7); } +/** + * Test Silhouette Score + */ +BOOST_AUTO_TEST_CASE(SilhouetteScoreTest) +{ + arma::mat X; + X << 0 << 1 << 1 << 0 << 0 << arma::endr + << 0 << 1 << 2 << 0 << 0 << arma::endr + << 1 << 1 << 3 << 2 << 0 << arma::endr; + arma::Row labels = {0, 1, 2, 0, 0}; + metric::EuclideanDistance metric; + double silhouetteScore = SilhouetteScore::Overall(X, labels, metric); + BOOST_REQUIRE_CLOSE(silhouetteScore, 0.1121684822489150, 1e-5); +} + BOOST_AUTO_TEST_SUITE_END(); diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp new file mode 100644 index 0000000000..b50279fe9e --- /dev/null +++ b/src/mlpack/tests/facilities_test.cpp @@ -0,0 +1,60 @@ +/** + * @file facilities_test.cpp + * @author Khizir Siddiqui + * + * Test file for facilities in metrics. + * + * mlpack is free software; you may redistribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ + +#include +#include +#include +#include + +#include +#include "test_tools.hpp" + +using namespace mlpack; +using namespace mlpack::cv; + +BOOST_AUTO_TEST_SUITE(FacilitiesTest); + + +/** + * The unequal sizes for data and labels show throw an error. + */ +BOOST_AUTO_TEST_CASE(AssertSizesTest) +{ + // Load the dataset. + arma::mat dataset; + data::Load("iris_train.csv", dataset); + // Load the labels. + arma::Row labels; + data::Load("iris_test_labels.csv", labels); + + BOOST_REQUIRE_THROW( + AssertSizes(dataset, labels, "test"), std::invalid_argument); +} + + +/** + * Pairwise distances. + */ +BOOST_AUTO_TEST_CASE(PairwiseDistanceTest) +{ + arma::mat X; + X << 0 << 1 << 1 << 0 << 0 << arma::endr + << 0 << 1 << 2 << 0 << 0 << arma::endr + << 1 << 1 << 3 << 2 << 0 << arma::endr; + metric::EuclideanDistance metric; + arma::mat dist = PairwiseDistances(X, metric); + BOOST_REQUIRE_EQUAL(dist(0, 0), 0); + BOOST_REQUIRE_CLOSE(dist(1, 0), 1.41421, 1e-3); + BOOST_REQUIRE_EQUAL(dist(2, 0), 3); +} + +BOOST_AUTO_TEST_SUITE_END();