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