From d59a3a969861885c137bfc449cf11ff7268fa3a9 Mon Sep 17 00:00:00 2001 From: Selmane Lebdaoui <selmane.lebdaoui@inria.fr> Date: Tue, 16 Jun 2020 10:10:38 +0200 Subject: [PATCH] Add a julia wrapper to spm with some testings --- .gitlab-ci.yml | 2 +- .gitlab/build.yml | 4 +- .gitlab/pages.yml | 4 +- .gitlab/test.yml | 4 +- tools/gen_wrappers.py | 38 ++++ tools/wrappers/__init__.py | 1 + tools/wrappers/wrap_julia.py | 245 +++++++++++++++++++++++++ wrappers/CMakeLists.txt | 3 +- wrappers/julia/CMakeLists.txt | 138 ++++++++++++++ wrappers/julia/spm/Manifest.mpi.toml | 114 ++++++++++++ wrappers/julia/spm/Manifest.shm.toml | 42 +++++ wrappers/julia/spm/Project.mpi.toml | 9 + wrappers/julia/spm/Project.shm.toml | 8 + wrappers/julia/spm/src/spm.jl | 201 ++++++++++++++++++++ wrappers/julia/spm/src/spm_enums.jl.in | 114 ++++++++++++ wrappers/julia/spm_driver.jl | 64 +++++++ wrappers/julia/spm_user.jl | 159 ++++++++++++++++ 17 files changed, 1142 insertions(+), 8 deletions(-) create mode 100644 tools/wrappers/wrap_julia.py create mode 100644 wrappers/julia/CMakeLists.txt create mode 100644 wrappers/julia/spm/Manifest.mpi.toml create mode 100644 wrappers/julia/spm/Manifest.shm.toml create mode 100644 wrappers/julia/spm/Project.mpi.toml create mode 100644 wrappers/julia/spm/Project.shm.toml create mode 100644 wrappers/julia/spm/src/spm.jl create mode 100644 wrappers/julia/spm/src/spm_enums.jl.in create mode 100755 wrappers/julia/spm_driver.jl create mode 100755 wrappers/julia/spm_user.jl diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3c6f8358..55172605 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ stages: before_script: - git submodule update --init --recursive - source .gitlab/env.sh - - mkdir -p build + - mkdir -p build-${VERSION} include: - .gitlab/common.yml diff --git a/.gitlab/build.yml b/.gitlab/build.yml index ad5fb509..a37e1bf0 100644 --- a/.gitlab/build.yml +++ b/.gitlab/build.yml @@ -8,10 +8,10 @@ untracked: true paths: - install-${VERSION} - - build + - build-${VERSION} - spm-build-${VERSION}.log script: - - cd build + - cd build-${VERSION} - cmake -DSPM_CI_VERSION=${VERSION} -C ../.gitlab/ci-test-initial-cache.cmake .. - make -j 4 | tee ../spm-build-${VERSION}.log diff --git a/.gitlab/pages.yml b/.gitlab/pages.yml index c6d9d775..df11debb 100644 --- a/.gitlab/pages.yml +++ b/.gitlab/pages.yml @@ -7,8 +7,8 @@ pages: paths: - public script: - - mkdir -p build - - cd build + - mkdir -p build-doc + - cd build-doc - cmake .. -DSPM_CI_VERSION=doc -C ../.gitlab/ci-test-initial-cache.cmake - make -j5 diff --git a/.gitlab/test.yml b/.gitlab/test.yml index 56444236..6290fa9e 100644 --- a/.gitlab/test.yml +++ b/.gitlab/test.yml @@ -10,14 +10,14 @@ - spm-gcov-${VERSION}.log script: - source install-${VERSION}/bin/spm_env.sh - - (cd build && + - (cd build-${VERSION} && eval "ctest $TESTS_RESTRICTION -D ExperimentalTest -D ExperimentalCoverage -D ExperimentalSubmit | tee -a ../spm-build-${VERSION}.log") - - lcov --capture --directory build + - lcov --capture --directory build-${VERSION} -q --output-file spm-${VERSION}-${RUN}.lcov | tee -a spm-gcov-${VERSION}.log diff --git a/tools/gen_wrappers.py b/tools/gen_wrappers.py index f5ffff60..403a4e43 100755 --- a/tools/gen_wrappers.py +++ b/tools/gen_wrappers.py @@ -489,6 +489,13 @@ spm_enums = { 'footer' : enums_fortran_footer, 'enums' : { 'mtxtype' : " enumerator :: SpmSymPosDef = SpmConjTrans + 1\n enumerator :: SpmHerPosDef = SpmConjTrans + 2\n" } }, + 'julia' : { 'filename' : "wrappers/julia/spm/src/spm_enums.jl.in", + 'description' : "SPM julia wrapper to define enums and datatypes", + 'header' :"const spm_int_t = @SPM_JULIA_INTEGER@\n" + "const spm_mpi_enabled = @SPM_MPI_ENABLED@\n", + 'footer' : "", + 'enums' : {} + }, } spm = { @@ -521,6 +528,32 @@ spm = { 'footer' : "", 'enums' : {} }, + 'julia' : { 'filename' : "wrappers/julia/spm/src/spm.jl", + 'description' : "SPM julia wrapper", + 'header' : "module spm\n" + "using CBinding\n" + "using Libdl\n" + "include(\"spm_enums.jl\")\n\n" + "function spm_library_path()\n" + " x = Libdl.dlext\n" + " return \"libspm.$x\"\n" + "end\n" + "libspm = spm_library_path()\n\n" + "if spm_mpi_enabled\n" + " using MPI\n MPI.Init()\nend\n\n" + "function __get_mpi_type__()\n" + " if !spm_mpi_enabled\n" + " return Cint\n" + " elseif sizeof(MPI.MPI_Comm) == sizeof(Clong)\n" + " return Clong\n" + " elseif sizeof(MPI.MPI_Comm) == sizeof(Cint)\n" + " return Cint\n" + " end\n" + " return Cvoid\n" + "end\n", + 'footer' : "end #module", + 'enums' : {} + }, } def main(): @@ -569,5 +602,10 @@ def main(): enum_list, struct_list, function_list) print( "Exported file: " + modulefilename ) + modulefilename = write_module( f['julia'], False, + wrappers.wrap_julia, + enum_list, struct_list, function_list) + print( "Exported file: " + modulefilename ) + # execute the program main() diff --git a/tools/wrappers/__init__.py b/tools/wrappers/__init__.py index c71a7d1e..17e01a2a 100644 --- a/tools/wrappers/__init__.py +++ b/tools/wrappers/__init__.py @@ -38,3 +38,4 @@ __all__ = [ 'return_variables_dict', 'derived_types', 'arrays_names_1D', 'arrays from .wrap_python import * from .wrap_fortran import * +from .wrap_julia import * diff --git a/tools/wrappers/wrap_julia.py b/tools/wrappers/wrap_julia.py new file mode 100644 index 00000000..3d39fcce --- /dev/null +++ b/tools/wrappers/wrap_julia.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python +""" +Wrapper Julia +============== + + @file wrappers/wrap_julia.py + + PaStiX generator for the wrapper + + @copyright 2019-2020 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + Univ. Bordeaux. All rights reserved. + + @version 6.0.0 + @author Mathieu Faverge + @author Selmane LEBDAOUI + @date 2020-06-18 + +""" +import os +import re +import argparse +from . import * + +indent=" " +iindent=4 + +# translation_table of types +types_dict = { + "int": ("Cint"), + "int8_t": ("Int8"), + "spm_coeftype_t": ("spm_coeftype_t"), + "spm_dir_t": ("spm_dir_t"), + "spm_trans_t": ("spm_trans_t"), + "spm_uplo_t": ("spm_uplo_t"), + "spm_diag_t": ("spm_diag_t"), + "spm_side_t": ("spm_side_t"), + "spm_driver_t": ("spm_driver_t"), + "spm_fmttype_t": ("spm_fmttype_t"), + "spm_layout_t": ("spm_layout_t"), + "spm_normtype_t": ("spm_normtype_t"), + "spm_rhstype_t": ("spm_rhstype_t"), + "spm_mtxtype_t": ("spm_mtxtype_t"), + "spm_int_t": ("spm_int_t"), + "spmatrix_t": ("spmatrix_t"), + "size_t": ("Csize_t"), + "char": ("Cchar"), + "double": ("Cdouble"), + "float": ("Cfloat"), + "void": ("Cvoid"), + "MPI_Comm": ("__get_mpi_type__()"), + "FILE": ("Cvoid"), +} + +def iso_c_interface_type(arg, return_value, args_list, args_size): + """Generate a declaration for a variable in the interface.""" + + is_double_ptr = False + if (arg[1] == "*" or arg[1] == "**" ): + is_pointer = True + elif (arg[1] == "**"): + is_double_ptr = True + else: + is_pointer = False + + f_type = types_dict[arg[0]] + if is_pointer: + if f_type == "Cvoid": + f_type = "Ptr{Cvoid}" + elif f_type == "Cchar": + f_type = "Cstring" + elif f_type == "Cint": + f_type = "Ptr{Cint}" + else: + f_type = "Ptr{"+f_type+"}" + if is_double_ptr: + f_type = "Ptr{" + f_type + "}" + + if (not return_value and arg[1] != "**"): + f_pointer = "value" + else: + f_pointer = "" + + f_name = format("%s::" % arg[2] ) + + args_size[0] = max(args_size[0], len(f_name)) + args_size[1] = max(args_size[1], len(f_type)) + args_list.append( [ f_name, f_type ] ); + +class wrap_julia: + + @staticmethod + def header( f ): + filename = os.path.basename( f['filename'] ) + filename = re.sub(r"\.in", "", filename) + header = '''#= + + @file ''' + filename + ''' + + ''' + f['description'] + ''' + + @copyright 2019-2020 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + Univ. Bordeaux. All rights reserved. + + @version 6.0.0 + @author Mathieu Faverge + @author Lebdaoui selmane + @date 2020-06-18 + +This file has been automatically generated with gen_wrappers.py + +=# +''' + if f['header'] != "": + header += "\n" + f['header'] + return header; + + @staticmethod + def footer( f ): + filename = os.path.basename( f['filename'] ) + modname = re.sub(r".f90", "", filename, flags=re.IGNORECASE) + footer = f['footer'] + return footer + + @staticmethod + def enum( f, enum ): + """Generate an interface for an enum. + Translate it into constants.""" + ename = enum[0] + params = enum[1] + # initialize a string with the fortran interface + bib = "" + Bib = "" + if ("SPM" in f['description']): + bib = "spm_" + Bib = "Spm" + elif ("Pastix" in f['description']): + bib = "pastix_" + Bib = "PASTIX" + py_interface = "@cenum " + bib + ename + "_t " + "{\n" + + # loop over the arguments of the enum to get max param length + length=0 + for param in params: + if ename == "mtxtype": + param[1] = re.sub(r"trans.", Bib, param[1]) + length = max( length, len(param[0])) + fmt="%-"+ str(length) + "s" + + # loop over the arguments of the enum + #Ename=""#ename[0].upper()+ename[1:] + suffix="" + if ename == "error": + Bib="SPM_ERR_" + elif ename == "rhstype": + Bib+="Rhs" + elif ename == "driver": + Bib+="Driver" + elif ename == "dir": + Bib+="Dir" + elif ename == "normtype": + length+=iindent + fmt="%-"+ str(length) + "s" + suffix="Norm" + for param in params: + name = param[0] + value = str(param[1]) + if(ename == "error" and name=="SUCCESS"): + py_interface += indent + "SPM_" + format(fmt % name) + indent + " = " + value + ",\n" + else : + py_interface += indent + Bib + format(fmt % (name + suffix)) + " = " + value + ",\n" + + py_interface+="}\n" + return py_interface + + @staticmethod + def struct(struct): + """Generate an interface for a struct. + Translate it into a derived type.""" + + # initialize a string with the fortran interface + py_interface = "" + + s = 0 + name = struct[0][2] + name = re.sub(r"pastix_", "", name) + py_interface += "@cstruct " + name + " {\n" + s = iindent + py_interface += s*" " + headline = s*" " + + slist = [] + ssize = [ 0, 0 ] + + # loop over the arguments of the enum + for j in range(1,len(struct)): + iso_c_interface_type(struct[j], True, slist, ssize) + + s += iindent + + for j in range(0,len(slist)): + if (j > 0): + py_interface += "\n" + headline + py_interface += format(slist[j][0] + slist[j][1]) + + py_interface += "\n}\n" + return py_interface + + @staticmethod + def function(function): + """Generate an interface for a function.""" + + return_type = function[0][0] + return_pointer = function[0][1] + + # is it a function or a subroutine + if (return_type == "void"): + is_function = False + else: + is_function = True + + c_symbol = function[0][2] + if "pastix" in c_symbol: + libname = "libpastix" + prefix = "" + elif "spm" in c_symbol: + libname = "libspm" + prefix = "" + else: + print("ERROR: function name without pastix nor spm") + return + cbinding_line = "@cbindings " + libname + " begin\n" + func_line = indent + "@cextern " + c_symbol + "( " + slist = [] + ssize = [ 0, 0 ] + for j in range(1,len(function)): + iso_c_interface_type(function[j], True, slist, ssize) + for j in range(0,len(slist)): + func_line += format(slist[j][0] + slist[j][1]) + if (j != len(slist)-1): + func_line += ", " + else : + func_line += " " + func_line+= ")::"+types_dict[return_type] + py_interface=cbinding_line + func_line + "\nend\n" + return py_interface diff --git a/wrappers/CMakeLists.txt b/wrappers/CMakeLists.txt index cf763161..295b00ef 100644 --- a/wrappers/CMakeLists.txt +++ b/wrappers/CMakeLists.txt @@ -15,6 +15,7 @@ endif() if (BUILD_SHARED_LIBS) add_subdirectory( python ) + add_subdirectory( julia ) else() - message(STATUS "--- Python wrapper is disabled with static libraries") + message(STATUS "--- Python and Julia wrappers are disabled with static libraries") endif() diff --git a/wrappers/julia/CMakeLists.txt b/wrappers/julia/CMakeLists.txt new file mode 100644 index 00000000..a0eacb8d --- /dev/null +++ b/wrappers/julia/CMakeLists.txt @@ -0,0 +1,138 @@ +### +# +# @copyright 2017-2018 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, +# Univ. Bordeaux. All rights reserved. +# +# @version 6.0.0 +# @author Mathieu Faverge +# @author Selmane Lebdaoui +# @date 2020-06-19 +# +### + +# Configure enum.py +if (SPM_INT64) + set(SPM_JULIA_INTEGER Int64) +else() + set(SPM_JULIA_INTEGER Int32) +endif() + +if (SPM_WITH_MPI) + set(SPM_JULIA_MPI_ENABLED true) +else() + set(SPM_JULIA_MPI_ENABLED false) +endif() + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/spm/src/spm_enums.jl.in" + "${CMAKE_CURRENT_BINARY_DIR}/spm/src/spm_enums.jl" @ONLY) + +# Copy wrapper to build +if ( SPM_WITH_MPI ) + file(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/spm/Project.mpi.toml + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/spm ) + file(RENAME + ${CMAKE_CURRENT_BINARY_DIR}/spm/Project.mpi.toml + ${CMAKE_CURRENT_BINARY_DIR}/spm/Project.toml ) +else() + file(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/spm/Project.shm.toml + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/spm ) + file(RENAME + ${CMAKE_CURRENT_BINARY_DIR}/spm/Project.shm.toml + ${CMAKE_CURRENT_BINARY_DIR}/spm/Project.toml ) +endif() + +file(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/spm/src/spm.jl + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/spm/src ) + +# Copy examples to build +file(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/spm_driver.jl + ${CMAKE_CURRENT_SOURCE_DIR}/spm_user.jl + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/spm/examples ) + +# Install julia package +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/spm/Project.toml + DESTINATION lib/julia/spm ) +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/spm/src/spm.jl + ${CMAKE_CURRENT_BINARY_DIR}/spm/src/spm_enums.jl + DESTINATION lib/julia/spm/src ) + +# Install julia examples +install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/spm_driver.jl + ${CMAKE_CURRENT_SOURCE_DIR}/spm_user.jl + DESTINATION lib/julia/spm/examples ) + +find_program( Julia_EXECUTABLE julia DOC "Julia executable" ) +if(Julia_EXECUTABLE) + execute_process( + COMMAND "${Julia_EXECUTABLE}" --startup-file=no --version + OUTPUT_VARIABLE Julia_VERSION_STRING + ) + string( + REGEX REPLACE ".*([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" + Julia_VERSION_STRING "${Julia_VERSION_STRING}" + ) + + message( STATUS "Julia Version: ${Julia_VERSION_STRING}") + + if ( ${Julia_VERSION_STRING} VERSION_LESS "1.4.0" ) + message( STATUS "Julia CTests: Disabled" ) + set( Julia_ENABLE_TESTS OFF ) + else() + message( STATUS "Julia CTests: Enabled" ) + set( Julia_ENABLE_TESTS ON ) + endif() +endif() + +if ( Julia_ENABLE_TESTS ) + + set( Julia_DEPOT_PATH ${CMAKE_CURRENT_BINARY_DIR}/depot ) + set( Julia_MPI_BINARY "system" ) + set( Julia_ENVIRONEMENT "JULIA_DEPOT_PATH=${Julia_DEPOT_PATH}" "JULIA_MPI_BINARY=${Julia_MPI_BINARY}" ) + + # + # Make sure the SPM package is built before use, and if necessary + # with the correct MPI before execution of the actual testings + # + if ( SPM_WITH_MPI ) + set( _julia_init_ ${Julia_EXECUTABLE} "--project" "-e" "using Pkg\; Pkg.activate(\"spm\")\; Pkg.instantiate()\; Pkg.build(\"MPI\")" ) + else() + set( _julia_init_ ${Julia_EXECUTABLE} "--project" "-e" "using Pkg\; Pkg.activate(\"spm\")\; Pkg.instantiate()" ) + endif() + + add_test( shm_julia_set_mpi ${_julia_init_} ) + set_tests_properties( shm_julia_set_mpi + PROPERTIES ENVIRONMENT "${Julia_ENVIRONEMENT}" ) + if ( SPM_WITH_MPI ) + add_test( mpi_julia_set_mpi ${_julia_init_} ) + set_tests_properties( mpi_julia_set_mpi + PROPERTIES ENVIRONMENT "${Julia_ENVIRONEMENT}" ) + endif() + + set( JULIA_TESTS + spm_driver spm_user ) + + foreach( example ${JULIA_TESTS} ) + set( _test_suffix_ julia_${example} ) + set( _test_file_ ${CMAKE_CURRENT_BINARY_DIR}/spm/examples/${example}.jl ) + + set( _test_name_ shm_${_test_suffix_} ) + add_test( ${_test_name_} ${Julia_EXECUTABLE} ${_test_file_} ) + set_tests_properties( ${_test_name_} + PROPERTIES ENVIRONMENT "${Julia_ENVIRONEMENT}" ) + + if (SPM_WITH_MPI) + set( _test_name_ mpi_${_test_suffix_} ) + add_test( ${_test_name_} mpiexec -np 4 --host localhost:4 ${Julia_EXECUTABLE} ${_test_file_} ) + set_tests_properties( ${_test_name_} + PROPERTIES ENVIRONMENT "${Julia_ENVIRONEMENT}" ) + endif() + endforeach() +endif() diff --git a/wrappers/julia/spm/Manifest.mpi.toml b/wrappers/julia/spm/Manifest.mpi.toml new file mode 100644 index 00000000..bf693d9e --- /dev/null +++ b/wrappers/julia/spm/Manifest.mpi.toml @@ -0,0 +1,114 @@ +# This file is machine-generated - editing it directly is not advised + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[CBinding]] +deps = ["Libdl", "Random", "Test"] +git-tree-sha1 = "6d8e70f3f63d78441d2000f09f062ec1f220409f" +uuid = "d43a6710-96b8-4a2d-833c-c424785e5374" +version = "0.9.0" + +[[CompilerSupportLibraries_jll]] +deps = ["Libdl", "Pkg"] +git-tree-sha1 = "7c4f882c41faa72118841185afc58a2eb00ef612" +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "0.3.3+0" + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[DocStringExtensions]] +deps = ["LibGit2", "Markdown", "Pkg", "Test"] +git-tree-sha1 = "c5714d9bcdba66389612dc4c47ed827c64112997" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.8.2" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[LibGit2]] +deps = ["Printf"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[MPI]] +deps = ["Distributed", "DocStringExtensions", "Libdl", "MPICH_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "Pkg", "Random", "Requires", "Serialization", "Sockets"] +git-tree-sha1 = "925f4e00b51d7a68ecb88c1b60d3b7aefb8c8fcb" +uuid = "da04e1cc-30fd-572f-bb4f-1f8673147195" +version = "0.15.0" + +[[MPICH_jll]] +deps = ["CompilerSupportLibraries_jll", "Libdl", "Pkg"] +git-tree-sha1 = "4d37f1e07b4e2a74462eebf9ee48c626d15ffdac" +uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" +version = "3.3.2+10" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[MicrosoftMPI_jll]] +deps = ["Libdl", "Pkg"] +git-tree-sha1 = "720de13004e416f2864c92593d3839e062703985" +uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" +version = "10.1.2+3" + +[[OpenMPI_jll]] +deps = ["Libdl", "Pkg"] +git-tree-sha1 = "41b983e26a7ab8c9bf05f7d70c274b817d541b46" +uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" +version = "4.0.2+2" + +[[Pkg]] +deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "d37400976e98018ee840e0ca4f9d20baa231dc6b" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.0.1" + +[[SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[Test]] +deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/wrappers/julia/spm/Manifest.shm.toml b/wrappers/julia/spm/Manifest.shm.toml new file mode 100644 index 00000000..7c7af016 --- /dev/null +++ b/wrappers/julia/spm/Manifest.shm.toml @@ -0,0 +1,42 @@ +# This file is machine-generated - editing it directly is not advised + +[[Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[CBinding]] +deps = ["Libdl", "Random", "Test"] +git-tree-sha1 = "6d8e70f3f63d78441d2000f09f062ec1f220409f" +uuid = "d43a6710-96b8-4a2d-833c-c424785e5374" +version = "0.9.0" + +[[Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[Random]] +deps = ["Serialization"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[Test]] +deps = ["Distributed", "InteractiveUtils", "Logging", "Random"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/wrappers/julia/spm/Project.mpi.toml b/wrappers/julia/spm/Project.mpi.toml new file mode 100644 index 00000000..e3d5b02d --- /dev/null +++ b/wrappers/julia/spm/Project.mpi.toml @@ -0,0 +1,9 @@ +name = "spm" +uuid = "a377bf9a-fa07-4e5f-a9da-e850a1f47d99" +authors = ["Selmane Lebdaoui <selmane.lebdaoui@inria.fr>"] +version = "0.1.0" + +[deps] +CBinding = "d43a6710-96b8-4a2d-833c-c424785e5374" +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" diff --git a/wrappers/julia/spm/Project.shm.toml b/wrappers/julia/spm/Project.shm.toml new file mode 100644 index 00000000..b5f25e3f --- /dev/null +++ b/wrappers/julia/spm/Project.shm.toml @@ -0,0 +1,8 @@ +name = "spm" +uuid = "a377bf9a-fa07-4e5f-a9da-e850a1f47d99" +authors = ["Selmane Lebdaoui <selmane.lebdaoui@inria.fr>"] +version = "0.1.0" + +[deps] +CBinding = "d43a6710-96b8-4a2d-833c-c424785e5374" +Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/wrappers/julia/spm/src/spm.jl b/wrappers/julia/spm/src/spm.jl new file mode 100644 index 00000000..b6fb1156 --- /dev/null +++ b/wrappers/julia/spm/src/spm.jl @@ -0,0 +1,201 @@ +#= + + @file spm.jl + + SPM julia wrapper + + @copyright 2019-2020 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + Univ. Bordeaux. All rights reserved. + + @version 6.0.0 + @author Mathieu Faverge + @author Lebdaoui selmane + @date 2020-06-18 + +This file has been automatically generated with gen_wrappers.py + +=# +module spm +using CBinding +using Libdl +include("spm_enums.jl") + +function spm_library_path() + x = Libdl.dlext + return "libspm.$x" +end +libspm = spm_library_path() + +if spm_mpi_enabled + using MPI +end + +function __get_mpi_type__() + if !spm_mpi_enabled + return Cint + elseif sizeof(MPI.MPI_Comm) == sizeof(Clong) + return Clong + elseif sizeof(MPI.MPI_Comm) == sizeof(Cint) + return Cint + end + return Cvoid +end + +@cstruct spmatrix_t { + mtxtype::spm_mtxtype_t + flttype::spm_coeftype_t + fmttype::spm_fmttype_t + gN::spm_int_t + n::spm_int_t + gnnz::spm_int_t + nnz::spm_int_t + gNexp::spm_int_t + nexp::spm_int_t + gnnzexp::spm_int_t + nnzexp::spm_int_t + dof::spm_int_t + dofs::Ptr{spm_int_t} + layout::spm_layout_t + colptr::Ptr{spm_int_t} + rowptr::Ptr{spm_int_t} + loc2glob::Ptr{spm_int_t} + values::Ptr{Cvoid} + glob2loc::Ptr{spm_int_t} + clustnum::Cint + clustnbr::Cint + comm::__get_mpi_type__() +} + +@cbindings libspm begin + @cextern spmInit( spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmAlloc( spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmExit( spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmCopy( spm::Ptr{spmatrix_t} )::spmatrix_t +end + +@cbindings libspm begin + @cextern spmBase( spm::Ptr{spmatrix_t}, baseval::Cint )::Cvoid +end + +@cbindings libspm begin + @cextern spmFindBase( spm::Ptr{spmatrix_t} )::spm_int_t +end + +@cbindings libspm begin + @cextern spmConvert( ofmttype::Cint, ospm::Ptr{spmatrix_t} )::Cint +end + +@cbindings libspm begin + @cextern spmUpdateComputedFields( spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmGenFakeValues( spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmInitDist( spm::Ptr{spmatrix_t}, comm::__get_mpi_type__() )::Cvoid +end + +@cbindings libspm begin + @cextern spmScatter( spm::Ptr{spmatrix_t}, n::spm_int_t, loc2glob::Ptr{spm_int_t}, distByColumn::Cint, root::Cint, comm::__get_mpi_type__() )::spmatrix_t +end + +@cbindings libspm begin + @cextern spmGather( spm::Ptr{spmatrix_t}, root::Cint )::spmatrix_t +end + +@cbindings libspm begin + @cextern spmNorm( ntype::spm_normtype_t, spm::Ptr{spmatrix_t} )::Cdouble +end + +@cbindings libspm begin + @cextern spmMatVec( trans::spm_trans_t, alpha::Cdouble, spm::Ptr{spmatrix_t}, x::Ptr{Cvoid}, beta::Cdouble, y::Ptr{Cvoid} )::Cint +end + +@cbindings libspm begin + @cextern spmMatMat( trans::spm_trans_t, n::spm_int_t, alpha::Cdouble, A::Ptr{spmatrix_t}, B::Ptr{Cvoid}, ldb::spm_int_t, beta::Cdouble, C::Ptr{Cvoid}, ldc::spm_int_t )::Cint +end + +@cbindings libspm begin + @cextern spmScalMatrix( alpha::Cdouble, spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmScalVector( flt::spm_coeftype_t, alpha::Cdouble, n::spm_int_t, x::Ptr{Cvoid}, incx::spm_int_t )::Cvoid +end + +@cbindings libspm begin + @cextern spmSort( spm::Ptr{spmatrix_t} )::Cint +end + +@cbindings libspm begin + @cextern spmMergeDuplicate( spm::Ptr{spmatrix_t} )::spm_int_t +end + +@cbindings libspm begin + @cextern spmSymmetrize( spm::Ptr{spmatrix_t} )::spm_int_t +end + +@cbindings libspm begin + @cextern spmCheckAndCorrect( spm_in::Ptr{spmatrix_t}, spm_out::Ptr{spmatrix_t} )::Cint +end + +@cbindings libspm begin + @cextern spmGenRHS( type::spm_rhstype_t, nrhs::spm_int_t, spm::Ptr{spmatrix_t}, x::Ptr{Cvoid}, ldx::spm_int_t, b::Ptr{Cvoid}, ldb::spm_int_t )::Cint +end + +@cbindings libspm begin + @cextern spmCheckAxb( eps::Cdouble, nrhs::spm_int_t, spm::Ptr{spmatrix_t}, x0::Ptr{Cvoid}, ldx0::spm_int_t, b::Ptr{Cvoid}, ldb::spm_int_t, x::Ptr{Cvoid}, ldx::spm_int_t )::Cint +end + +@cbindings libspm begin + @cextern spmIntConvert( n::spm_int_t, input::Ptr{Cint} )::spm_int_t +end + +@cbindings libspm begin + @cextern spmLoad( spm::Ptr{spmatrix_t}, infile::Ptr{Cvoid} )::Cint +end + +@cbindings libspm begin + @cextern spmSave( spm::Ptr{spmatrix_t}, outfile::Ptr{Cvoid} )::Cint +end + +@cbindings libspm begin + @cextern spmReadDriver( driver::spm_driver_t, filename::Cstring, spm::Ptr{spmatrix_t} )::Cint +end + +@cbindings libspm begin + @cextern spmParseLaplacianInfo( filename::Cstring, flttype::Ptr{spm_coeftype_t}, dim1::Ptr{spm_int_t}, dim2::Ptr{spm_int_t}, dim3::Ptr{spm_int_t}, alpha::Ptr{Cdouble}, beta::Ptr{Cdouble}, dof::Ptr{spm_int_t} )::Cint +end + +@cbindings libspm begin + @cextern spm2Dense( spm::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmPrint( spm::Ptr{spmatrix_t}, f::Ptr{Cvoid} )::Cvoid +end + +@cbindings libspm begin + @cextern spmPrintInfo( spm::Ptr{spmatrix_t}, f::Ptr{Cvoid} )::Cvoid +end + +@cbindings libspm begin + @cextern spmExpand( spm_in::Ptr{spmatrix_t}, spm_out::Ptr{spmatrix_t} )::Cvoid +end + +@cbindings libspm begin + @cextern spmDofExtend( spm::Ptr{spmatrix_t}, type::Cint, dof::Cint )::spmatrix_t +end + +end #module diff --git a/wrappers/julia/spm/src/spm_enums.jl.in b/wrappers/julia/spm/src/spm_enums.jl.in new file mode 100644 index 00000000..b57ec429 --- /dev/null +++ b/wrappers/julia/spm/src/spm_enums.jl.in @@ -0,0 +1,114 @@ +#= + + @file spm_enums.jl + + SPM julia wrapper to define enums and datatypes + + @copyright 2019-2020 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + Univ. Bordeaux. All rights reserved. + + @version 6.0.0 + @author Mathieu Faverge + @author Lebdaoui selmane + @date 2020-06-18 + +This file has been automatically generated with gen_wrappers.py + +=# + +const spm_int_t = @SPM_JULIA_INTEGER@ +const spm_mpi_enabled = @SPM_JULIA_MPI_ENABLED@ + +@cenum spm_coeftype_t { + SpmPattern = 0, + SpmFloat = 2, + SpmDouble = 3, + SpmComplex32 = 4, + SpmComplex64 = 5, +} + +@cenum spm_fmttype_t { + SpmCSC = 0, + SpmCSR = 1, + SpmIJV = 2, +} + +@cenum spm_error_t { + SPM_SUCCESS = 0, + SPM_ERR_UNKNOWN = 1, + SPM_ERR_ALLOC = 2, + SPM_ERR_NOTIMPLEMENTED = 3, + SPM_ERR_OUTOFMEMORY = 4, + SPM_ERR_THREAD = 5, + SPM_ERR_INTERNAL = 6, + SPM_ERR_BADPARAMETER = 7, + SPM_ERR_FILE = 8, + SPM_ERR_INTEGER_TYPE = 9, + SPM_ERR_IO = 10, + SPM_ERR_MPI = 11, +} + +@cenum spm_driver_t { + SpmDriverRSA = 0, + SpmDriverHB = 1, + SpmDriverIJV = 2, + SpmDriverMM = 3, + SpmDriverLaplacian = 4, + SpmDriverXLaplacian = 5, + SpmDriverGraph = 6, + SpmDriverSPM = 7, +} + +@cenum spm_rhstype_t { + SpmRhsOne = 0, + SpmRhsI = 1, + SpmRhsRndX = 2, + SpmRhsRndB = 3, +} + +@cenum spm_layout_t { + SpmRowMajor = 101, + SpmColMajor = 102, +} + +@cenum spm_trans_t { + SpmNoTrans = 111, + SpmTrans = 112, + SpmConjTrans = 113, +} + +@cenum spm_mtxtype_t { + SpmGeneral = SpmNoTrans, + SpmSymmetric = SpmTrans, + SpmHermitian = SpmConjTrans, +} + +@cenum spm_uplo_t { + SpmUpper = 121, + SpmLower = 122, + SpmUpperLower = 123, +} + +@cenum spm_diag_t { + SpmNonUnit = 131, + SpmUnit = 132, +} + +@cenum spm_side_t { + SpmLeft = 141, + SpmRight = 142, +} + +@cenum spm_normtype_t { + SpmOneNorm = 171, + SpmFrobeniusNorm = 174, + SpmInfNorm = 175, + SpmMaxNorm = 177, +} + +@cenum spm_dir_t { + SpmDirForward = 391, + SpmDirBackward = 392, +} + + diff --git a/wrappers/julia/spm_driver.jl b/wrappers/julia/spm_driver.jl new file mode 100755 index 00000000..71b64fde --- /dev/null +++ b/wrappers/julia/spm_driver.jl @@ -0,0 +1,64 @@ +#!/usr/bin/env julia +#= + @file spm_driver.jl + + SPM example to generate a sparse matrix from the spm drivers + + @copyright 2019-2020 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + Univ. Bordeaux. All rights reserved. + + @version 6.0.0 + @author Mathieu Faverge + @author Selmane Lebdaoui + @date 2020-06-15 +=# +using Pkg +Pkg.activate("spm") +Pkg.instantiate() +using CBinding +using spm + +if spm.spm_mpi_enabled + using MPI + MPI.Init() +end + +# +# Two solutions to select the outpu file to pass to output functions +# +my_stdout = Libc.FILE( Libc.RawFD(1), "w" ) # Select the stdout or stderr through 1 or 2 +#my_stdout = Ptr{Cvoid}(0) # Give a null pointer to use the default + +A = spm.spmatrix_t(zero) +Aptr = Ptr{spm.spmatrix_t}(pointer_from_objref(A)) + +# Example from a HB file +#spm.spmReadDriver( spm.SpmDriverHB, "__SPM_DIR__/tests/matrix/orsirr.rua", Aptr ) + +# Example from the Laplacian generator driver +spm.spmReadDriver( spm.SpmDriverLaplacian, "10:10:10:2.:1.", Aptr ) + +spm.spmPrintInfo( Aptr, my_stdout ) + +# Scale A for low-rank: A / ||A||_f +norm = spm.spmNorm( spm.SpmFrobeniusNorm, Aptr ) +spm.spmScalMatrix( 1. / norm, Aptr ) + +# Generate b and x0 vectors such that A * x0 = b + +nrhs = 10 +n = A.nexp +X0 = zeros( Cdouble, (n, nrhs) ) +B = zeros( Cdouble, (n, nrhs) ) +X = zeros( Cdouble, (n, nrhs) ) + +spm.spmGenRHS( spm.SpmRhsRndX, nrhs, Aptr, X, n, B, n ) + +# Copy x0 into x for backup +X0 = copy(X) + +# Check that A * x = b +eps = 1.e-15 # Set to 1e-7 for single precision +spm.spmCheckAxb( eps, nrhs, Aptr, X0, n, B, n, X, n ) + +spm.spmExit( Aptr ) diff --git a/wrappers/julia/spm_user.jl b/wrappers/julia/spm_user.jl new file mode 100755 index 00000000..64ae67a9 --- /dev/null +++ b/wrappers/julia/spm_user.jl @@ -0,0 +1,159 @@ +#!/usr/bin/env julia +#= + @file spm_user.jl + + Julia spm example using a laplacian matrix. + + @copyright 2019-2020 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, + Univ. Bordeaux. All rights reserved. + + @version 6.0.0 + @author Mathieu Faverge + @author Selmane Lebdaoui + @date 2020-06-27 +=# +using Pkg +Pkg.activate("spm") +Pkg.instantiate() +using CBinding +using spm + +using Base +using Distributed + +if spm.spm_mpi_enabled + using MPI + MPI.Init() +end + +global A = spm.spmatrix_t(zero) +global Aptr = Ptr{spm.spmatrix_t}(pointer_from_objref(A)) + +# +# Two solutions to select the outpu file to pass to output functions +# +my_stdout = Libc.FILE( Libc.RawFD(1), "w" ) # Select the stdout or stderr through 1 or 2 +#my_stdout = Ptr{Cvoid}(0) # Give a null pointer to use the default + +# +#Generate a 10x10x10 complex Laplacian in IJV format +# +dim1 = 10 +dim2 = 10 +dim3 = 10 +n = dim1 * dim2 * dim3 +nnz = (2*(dim1)-1) * dim2 * dim3 + (dim2-1)*dim1*dim3 + dim2*dim1*(dim3-1) + +#Create the spm out of the internal data + +spm.spmInit( Aptr ) +A.mtxtype = spm.SpmSymmetric +A.flttype = spm.SpmDouble +A.fmttype = spm.SpmIJV +A.n = n +A.nnz = nnz +A.dof = 1 + +spm.spmUpdateComputedFields( Aptr ) +spm.spmAlloc( Aptr ) + +row = zeros( spm.spm_int_t, nnz ) +col = zeros( spm.spm_int_t, nnz ) +val = zeros( Cdouble, nnz ) + +global m = 1 + +for i in 1:dim1 + for j in 1:dim2 + for k in 1:dim3 + global m + row[m] = (i-1) + dim1 * (j-1) + dim1 * dim2 * (k-1) + 1 + col[m] = (i-1) + dim1 * (j-1) + dim1 * dim2 * (k-1) + 1 + val[m] = 6. + if i == 1 + val[m] = val[m] - 1. + end + if i == dim1 + val[m] = val[m] - 1. + end + if j == 1 + val[m] = val[m] - 1. + end + if j == dim2 + val[m] = val[m] - 1. + end + if k == 1 + val[m] = val[m] - 1. + end + if k == dim3 + val[m] = val[m] - 1. + end + val[m] = val[m] * 8. + m = m + 1 + if i < dim1 + row[m] = i + dim1 * (j-1) + dim1 * dim2 * (k-1) + 1 + col[m] = (i-1) + dim1 * (j-1) + dim1 * dim2 * (k-1) + 1 + val[m] = - 1. + m = m + 1 + end + if j < dim2 + row[m] = (i-1) + dim1 * j + dim1 * dim2 * (k-1) + 1 + col[m] = (i-1) + dim1 * (j-1) + dim1 * dim2 * (k-1) + 1 + val[m] = - 1. + m = m + 1 + end + if k < dim3 + row[m] = (i-1) + dim1 * (j-1) + dim1 * dim2 * k + 1 + col[m] = (i-1) + dim1 * (j-1) + dim1 * dim2 * (k-1) + 1 + val[m] = -1. + m = m + 1 + end + end + end +end + +if m != nnz+1 + println( "m ", m, "nnz ", nnz ) +end + +A.colptr = pointer( col ) +A.rowptr = pointer( row ) +A.values = pointer( val ) + +A2 = spm.spmatrix_t( zero ) +A2ptr = Ptr{spm.spmatrix_t}( pointer_from_objref(A2) ) +rc = spm.spmCheckAndCorrect( Aptr, A2ptr ) + +if rc != 0 + spm.spmExit( Aptr ) + clear!( :A ) + clear!( :Aptr ) + A = A2 + Aptr = A2ptr +end + +spm.spmPrintInfo( Aptr, my_stdout ) + +# 2- The right hand side + +nrhs = 10 +x0 = zeros( Cdouble, ( A.nexp, nrhs ) ) +b = zeros( Cdouble, ( A.nexp, nrhs ) ) +x = zeros( Cdouble, ( A.nexp, nrhs ) ) + +spm.spmGenRHS( spm.SpmRhsRndX, nrhs, Aptr, x0, n, b, n ) + +# Copy x0 into x for backup +x = x0 + +# Check that A * x = b +eps = 1.e-15 # Set to 1e-7 for single precision +spm.spmCheckAxb( eps, nrhs, Aptr, x, n, b, n, x0, n ) + +spm.spmExit( Aptr ) + +clear!( :A ) +clear!( :Aptr ) +clear!( :b ) +clear!( :x ) +clear!( :x0 ) -- GitLab