{"id":32647124,"url":"https://github.com/mikayelgr/dmm","last_synced_at":"2026-07-10T10:31:27.582Z","repository":{"id":320764141,"uuid":"1083226449","full_name":"mikayelgr/dmm","owner":"mikayelgr","description":"Dense matrix multiplication and equivalence bindings for the JVM via Java Native Interface (JNI) and Kotlin Native from the Eigen C++ linear algebra library.","archived":false,"fork":false,"pushed_at":"2025-10-27T07:51:41.000Z","size":164,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-01T23:36:02.458Z","etag":null,"topics":["c","cmake","cpp","eigen3","gradle","java","kotlin","make"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikayelgr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-25T15:41:25.000Z","updated_at":"2025-10-27T07:51:44.000Z","dependencies_parsed_at":"2025-10-25T19:35:32.632Z","dependency_job_id":null,"html_url":"https://github.com/mikayelgr/dmm","commit_stats":null,"previous_names":["mikayelgr/dmm"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mikayelgr/dmm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikayelgr%2Fdmm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikayelgr%2Fdmm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikayelgr%2Fdmm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikayelgr%2Fdmm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikayelgr","download_url":"https://codeload.github.com/mikayelgr/dmm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikayelgr%2Fdmm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35329609,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-10T02:00:06.465Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","cmake","cpp","eigen3","gradle","java","kotlin","make"],"created_at":"2025-10-31T05:03:22.116Z","updated_at":"2026-07-10T10:31:27.574Z","avatar_url":"https://github.com/mikayelgr.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/mikayelgr/dmm/actions/workflows/test-build.yml/badge.svg)](https://github.com/mikayelgr/dmm/actions/workflows/test-build.yml)\n\n# DMM - Dense Matrix Multiplication\n\nDMM is a simple project exposes a few dense matrix multiplication functions from C++ to the JVM. The implementation is based on the [Eigen C++ library for Linear Algebra](https://eigen.tuxfamily.org/index.php?title=Main_Page) for implementing most of the multiplication functionality as efficiently as possible. I could have implemented it from scratch but existing solutions utilize the power of the modern CPUs much better using single instruction, multiple data (SIMD) and fused multiply-add (FMA) instructions. The project is supported on Linux and macOS. Support on Windows has not been tested.\n\n\u003e Note: this project has been created as a solution for the task for the JetBrains' \"Graphite rendering backend support in Skiko and Compose Multiplatform\" internship during 2025. This code has been authored by Mikayel Grigoryan.\n\n## Introduction\n\n\u003e This guide is only applicable to macOS, however, the project itself can be built on most systems, including macOS, Linux, and Windows. The behavior of this library has been optimized for macOS specifically.\n\nTo be able to build and test this project there are a few prerequisites. You will need to install the following packages using brew or your favorite package manager:\n\n- CMake version \u003e=4.1.2\n- Eigen C++ version 3.4.1\n- OpenJDK 21\n- Git (from XCode toolchain)\n- GNU Make (from XCode toolchain)\n- Apple clang version 17.0.0 (from XCode toolchain)\n- Apple clang++ version 17.0.0 (from XCode toolchain)\n\nTo install these packages on macOS, you must use `brew` and `xcode-select`. Just copy and paste the following command inside your terminal for the packages to be installed:\n\n```bash\nbrew install cmake eigen openjdk@21\nxcode-select --install\n```\n\nWhen prompted by XCode, make sure to agree with the license agreements and follow the instructions on the screen. As a final measure, on macOS, you will additionally need to run the following command, to make sure that programs like `cmake` and `make` are globally available:\n\n```bash\nsudo launchctl config user path /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin\n```\n\nOn macOS, GUI apps like IntelliJ are launched by the `launchd` daemon, which doesn’t inherit your shell’s environment variables — including `PATH`. Running `sudo launchctl config user path ...` fixes this by defining a global PATH for all user processes, so GUI-launched apps can find tools like CMake or Homebrew binaries.\n\n\u003e - https://stackoverflow.com/questions/135688/setting-environment-variables-on-os-x?utm_source=chatgpt.com\n\u003e - https://unix.stackexchange.com/questions/89076/how-to-set-the-path-osx-applications-use?utm_source=chatgpt.com\n\n## Structure\n\nThe project is structured in following directories:\n\n- `libdmm` - Contains the original C++ to JNI bindings for 2 functions, which are **multiplication** and **equivalence checking** of two matrices, both based on the [Eigen C++ library for Linear Algebra](https://eigen.tuxfamily.org/index.php?title=Main_Page). I decided to stand on the shoulders of giants and focus on maximizing the performance and enhancing readability.\n- `jvm` – Contains JNI implementation of the wrapper library for the JVM using Java, as well as tests, and benchmarks written in Java and Kotlin.\n- `kmp` - Contains Kotlin Native/Multiplatform bindings implementation, as well as tests, and benchmarks written in Kotlin.\n\n## Configuration\n\nThe `libdmm` directory contains the C++ source code of the implementation of the bridge interface. It exposes a few function from `src/dmm.cpp` using the Java Native Interface (JNI) so that the functions are accessible from any JVM language contexts. Before building, you must ensure that the `JAVA_HOME` environment variable is set. In our case, you can obtain the variable by entering:\n\n```bash\nbrew info openjdk@21\n```\n\nThis should return output similar to the following:\n```bash\n==\u003e openjdk@21: stable 21.0.9 (bottled) [keg-only]\nDevelopment kit for the Java programming language\nhttps://openjdk.org/\nInstalled\n/opt/homebrew/Cellar/openjdk@21/21.0.9 (600 files, 331.2MB)\n  Poured from bottle using the formulae.brew.sh API on 2025-10-25 at 17:38:53\nFrom: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/o/openjdk@21.rb\nLicense: GPL-2.0-only WITH Classpath-exception-2.0\n==\u003e Dependencies\nBuild: autoconf ✘, pkgconf ✘\nRequired: freetype ✔, giflib ✔, harfbuzz ✔, jpeg-turbo ✔, libpng ✔, little-cms2 ✔\n==\u003e Requirements\nBuild: Xcode (on macOS) ✔\n==\u003e Caveats\nFor the system Java wrappers to find this JDK, symlink it with\n  sudo ln -sfn /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-21.jdk\n\nopenjdk@21 is keg-only, which means it was not symlinked into /opt/homebrew,\nbecause this is an alternate version of another formula.\n\nIf you need to have openjdk@21 first in your PATH, run:\n  echo 'export PATH=\"/opt/homebrew/opt/openjdk@21/bin:$PATH\"' \u003e\u003e ~/.zshrc\n\nFor compilers to find openjdk@21 you may need to set:\n  export CPPFLAGS=\"-I/opt/homebrew/opt/openjdk@21/include\"\n==\u003e Analytics\ninstall: 21,972 (30 days), 60,964 (90 days), 211,180 (365 days)\ninstall-on-request: 15,401 (30 days), 42,560 (90 days), 131,855 (365 days)\nbuild-error: 75 (30 days)\n```\n\nFrom here, the main path for the OpenJDK 21 is going to be `/opt/homebrew/Cellar/openjdk@21/21.0.9`, and the `JAVA_HOME` environment variable will need to be set to `/opt/homebrew/Cellar/openjdk@21/21.0.9/libexec/openjdk.jdk/Contents/Home`. This setup is specific to macOS, specifically Apple silicon.\n\n### Building\n\nTo obtain the dynamic library for your specific platform, run the build process using CMake and assemble the files using GNU Make:\n\n```bash\ncd libdmm\ncmake -B ./build -S . \u0026\u0026 cd build \u0026\u0026 make \u0026\u0026 cd -\n```\n\nThis will assemble the dynamic library which can be linked to our JVM/Kotlin Multiplatform library. If the build succeeds, you will be able to find a `libdmm.dylib|.so|.dll` depending on your platform in the `libdmm/build` folder.\n\n### Building `libdmm` Manually Using CMake\n\nTo get the dynamic library for `libdmm` manually, you can run the following commands from the root directory of this project:\n\n```bash\ncd libdmm\ncmake -B build -S .\ncd build \u0026\u0026 make \u0026\u0026 cd -\n```\n\nThis will compile the dynamic library into a binary compatible only with your platform. You can find the generated binary under the `build` folder inside `libdmm`.\n\n\u003e Note that building on Windows has been tested once for now and failed due to missing dependencies. You can use your favorite Windows-native package manager in order to obtain the required libraries and binaries, in which case the library should compile in theory.\n\n### Verifying JNI Implementation\n\nTo verify the JNI implementation, you can use the Gradle wrapper that comes with the project in the `jvm` folder. This specific folder contains a JNI implementation of the library using Java. To verify that everything functions properly, you can run the following command from the root of the project:\n\n```bash\ncd jvm\n./gradlew test --console=plain\n```\n\n\u003e Note: in case of making changes to the C++ source code, it is a good idea to run the `clean` task explicitly as well (e.g. `./gradlew clean test`) before testing anything in order to make sure that you're not running the cached library. I'm not very familiar with Gradle and tried to do my best based on my research, so I might have made some mistakes while configuring its caching.\n\n### Verifying Kotlin Native Implementation\n\nThe project for Kotlin Native bindings has been boostrapped from the official repostiory at \u003chttps://github.com/Kotlin/kmp-native-wizard/\u003e. To verify that the K/N bindings are installed and functioning properly, run the following commands from the root of the project:\n\n```bash\ncd kmp\n./gradlew nativeTest\n```\n\n\u003e Kotlin Native implementation, similar to the JNI implementation, builds the library automatically via Gradle tasks before C interop process happens, to make sure all libraries exist.\n\n## Ending Notes\n\nWhile I have tried to implement WASM/JS support as well as benchmarking with kotlinx-benchmark framework, I was constantly hitting some weird issues with my benchmarks and some of the files not being recognized as actual benchmark files. I believe that this might be due to the fact that I'm new to the Kotlin Native platform. While I have tried using AI tools as well, they got me nowhere.\n\nFor that reason I have included my pure Kotlin implementation of the simple matrix multiplication algorithm below, in case we manage to benchmark them sometime:\n\n```kotlin\npackage com.mikayel.grigoryan\n\nfun mul(left: Array\u003cArray\u003cDouble\u003e\u003e, right: Array\u003cArray\u003cDouble\u003e\u003e): Array\u003cArray\u003cDouble\u003e\u003e {\n    val lDims = getMatrixDimensions(left)\n    val rDims = getMatrixDimensions(right)\n    validateMatrices(left, lDims, right, rDims)\n\n    val row1 = lDims[0]\n    val col1 = lDims[1]\n    val col2 = rDims[1]\n    val product = Array(row1) { Array(col2) { 0.0 } }\n\n    for (i in 0 until row1) {\n        for (j in 0 until col2) {\n            for (k in 0 until col1) {\n                product[i][j] += left[i][k] * right[k][j]\n            }\n        }\n    }\n\n    return product\n}\n\nprivate fun validateMatrices(\n    left: Array\u003cArray\u003cDouble\u003e\u003e, lDims: Array\u003cInt\u003e,\n    right: Array\u003cArray\u003cDouble\u003e\u003e, rDims: Array\u003cInt\u003e,\n) {\n    assert(validateMatrixCols(lDims, left)) { \"Left matrix is inconsistent\" }\n    assert(validateMatrixCols(rDims, right)) { \"Right matrix is inconsistent\" }\n    assert(lDims[1] == rDims[0]) { \"Number of columns of the left matrix != to number of rows on right matrix\" }\n}\n\nprivate fun getMatrixDimensions(matrix: Array\u003cArray\u003cDouble\u003e\u003e): Array\u003cInt\u003e {\n    val nRows = matrix.size\n    // Assuming the matrix is set to its first column's size\n    val nCols = matrix.getOrNull(nRows)?.size ?: 0\n    return arrayOf(nRows, nCols)\n}\n\nprivate fun validateMatrixCols(dims: Array\u003cInt\u003e, matrix: Array\u003cArray\u003cDouble\u003e\u003e): Boolean {\n    for (i in 0 until dims[0]) {\n        if (matrix[i].size != dims[1]) {\n            return false\n        }\n    }\n\n    return true\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikayelgr%2Fdmm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikayelgr%2Fdmm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikayelgr%2Fdmm/lists"}