Skip to content

Commit

Permalink
Merge pull request #391 from ankith26/ankith26-gsoc
Browse files Browse the repository at this point in the history
[GSoC 2024] Binding PyElastica with Elastica++
  • Loading branch information
skim0119 authored Sep 22, 2024
2 parents 558cabc + 2dfc94e commit 85ddf84
Show file tree
Hide file tree
Showing 479 changed files with 49,546 additions and 2,468 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/elasticapp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: elasticapp (Elastica++ based backend) tests

# trigger run only on changes to the backend folder.
on:
push:
paths:
- backend/**
pull_request:
paths:
- backend/**

jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.10", "3.11"] #, "3.12"]
os: [ubuntu-latest] # , macos-latest]

steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/[email protected]
with:
python-version: ${{ matrix.python-version }}

- name: Install PyElastica
run: pip install . -v

- name: Install elasticapp backend
run: pip install ./backend -v

- name: Run elasticapp tests
run: |
python -m pip install pytest
pytest backend/tests
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,6 @@ outcmaes/*

# csv files
*.csv

# ./backend dependencies
deps
17 changes: 17 additions & 0 deletions backend/.clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
# We'll use defaults from the Google style.
# See http://clang.llvm.org/docs/ClangFormat.html for help.
Language: Cpp
BasedOnStyle: Google
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
PointerAlignment: Left
DerivePointerAlignment: false
FixNamespaceComments: true
IncludeCategories:
- Regex: "^<.*"
Priority: 1
- Regex: ".*"
Priority: 2
NamespaceIndentation: All
SortIncludes: false
10 changes: 10 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@ install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps

subprojects/packagecache

subprojects/blaze
subprojects/blaze_tensor
subprojects/brigand
subprojects/cxxopts-3.1.1
subprojects/sleef
subprojects/tbb
subprojects/yaml-cpp
113 changes: 0 additions & 113 deletions backend/CMakeLists.txt

This file was deleted.

44 changes: 44 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Elasticapp backend for PyElastica

This file serves as the documentation for the `elasticapp` backend.

## Installation

In the root of the PyElastica source tree, run the following command

```
pip install ./backend
```

> Make sure you install the package from _PyElastica source tree_.
This command will take care of installation of all build-time dependencies, compilation of C++ source files and install the a python package called `elasticapp`.

## Testing

Make sure you have `pytest` installed. In the root of the PyElastica source tree, run the following command

```
pytest backend/tests
```

## Benchmarking

Standalone scripts for benchmarking purposes are available in `backend/benchmarking` folder.

### Benchmarking `matmul`

For benchmarking various `matmul` implementations, run

```
python3 backend/benchmarking/matmul.py
```

## Contributed By

- Tejaswin Parthasarathy (Teja)
- [Seung Hyun Kim](https://github.com/skim0119)
- Ankith Pai
- [Yashraj Bhosale](https://github.com/bhosale2)
- Arman Tekinalp
- Songyuan Cui
50 changes: 50 additions & 0 deletions backend/benchmarking/batchcross.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from elasticapp._linalg_numpy import batch_cross
from elasticapp._linalg import batch_cross as batch_cross_final
from elasticapp._PyArrays import Matrix
from elastica._linalg import _batch_cross
import numpy
import time

# warm up jit for fair comparison
random_1 = numpy.random.random((3, 1))
random_2 = numpy.random.random((3, 1))
out1 = _batch_cross(random_1, random_2)


def benchmark_batchsize(funcs: list, batches: list[int], num_iterations: int = 1000):
ret: dict = {}
for batch_size in batches:
random_a = numpy.random.random((3, batch_size))
random_b = numpy.random.random((3, batch_size))

ret[batch_size] = {}
for func_name, func, func_wrap in funcs:
random_a_w = func_wrap(random_a) if func_wrap else random_a
random_b_w = func_wrap(random_b) if func_wrap else random_b

start = time.perf_counter()
for _ in range(num_iterations):
func(random_a_w, random_b_w)

ret[batch_size][func_name] = (time.perf_counter() - start) / num_iterations

return ret


results = benchmark_batchsize(
[
("pyelastica", _batch_cross, None),
("elasticapp_blaze_copy", batch_cross, None),
("elasticapp_blaze_final", batch_cross_final, Matrix),
],
[2**i for i in range(14)],
)
for size, data in results.items():
pyelastica = data["pyelastica"]
elasticapp_blaze_copy = data["elasticapp_blaze_copy"]
elasticapp_blaze_final = data["elasticapp_blaze_final"]
print(f"{size = }")
print(f"{pyelastica = }")
print(f"{elasticapp_blaze_copy = }, ratio: {elasticapp_blaze_copy / pyelastica}")
print(f"{elasticapp_blaze_final = }, ratio: {elasticapp_blaze_final / pyelastica}")
print()
46 changes: 46 additions & 0 deletions backend/benchmarking/inv_rotate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from elasticapp._rotations import inv_rotate, inv_rotate_scalar
from elasticapp._PyArrays import Tensor
from elastica._rotations import _inv_rotate
import numpy
import time

# warm up jit for fair comparison
random_1 = numpy.random.random((3, 3, 1))
out1 = _inv_rotate(random_1)


def benchmark_batchsize(funcs: list, batches: list[int], num_iterations: int = 1000):
ret: dict = {}
for batch_size in batches:
random_a = numpy.random.random((3, 3, batch_size))

ret[batch_size] = {}
for func_name, func, func_wrap in funcs:
random_a_w = func_wrap(random_a) if func_wrap else random_a

start = time.perf_counter()
for _ in range(num_iterations):
func(random_a_w)

ret[batch_size][func_name] = (time.perf_counter() - start) / num_iterations

return ret


results = benchmark_batchsize(
[
("pyelastica", _inv_rotate, None),
("elasticapp_simd", inv_rotate, Tensor),
("elasticapp_scalar", inv_rotate_scalar, Tensor),
],
[2**i for i in range(14)],
)
for size, data in results.items():
pyelastica = data["pyelastica"]
elasticapp_simd = data["elasticapp_simd"]
elasticapp_scalar = data["elasticapp_scalar"]
print(f"{size = }")
print(f"{pyelastica = }")
print(f"{elasticapp_simd = }, ratio: {elasticapp_simd / pyelastica}")
print(f"{elasticapp_scalar = }, ratio: {elasticapp_scalar / pyelastica}")
print()
62 changes: 62 additions & 0 deletions backend/benchmarking/matmul.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from elasticapp._linalg_numpy import (
batch_matmul_naive,
batch_matmul_blaze,
batch_matmul,
)
from elasticapp._linalg import batch_matmul as batch_matmul_final
from elasticapp._PyArrays import Tensor
from elastica._linalg import _batch_matmul
import numpy
import time

# warm up jit for fair comparison
random_1 = numpy.random.random((3, 3, 1))
random_2 = numpy.random.random((3, 3, 1))
out1 = _batch_matmul(random_1, random_2)


def benchmark_batchsize(funcs: list, batches: list[int], num_iterations: int = 1000):
ret: dict = {}
for batch_size in batches:
random_a = numpy.random.random((3, 3, batch_size))
random_b = numpy.random.random((3, 3, batch_size))

ret[batch_size] = {}
for func_name, func, func_wrap in funcs:
random_a_w = func_wrap(random_a) if func_wrap else random_a
random_b_w = func_wrap(random_b) if func_wrap else random_b

start = time.perf_counter()
for _ in range(num_iterations):
func(random_a_w, random_b_w)

ret[batch_size][func_name] = (
time.perf_counter() - start
) / num_iterations

return ret


results = benchmark_batchsize(
[
("pyelastica", _batch_matmul, None),
("elasticapp_naive", batch_matmul_naive, None),
("elasticapp_blaze", batch_matmul_blaze, None),
("elasticapp_blaze_copy", batch_matmul, None),
("elasticapp_blaze_final", batch_matmul_final, Tensor),
],
[2**i for i in range(14)],
)
for size, data in results.items():
pyelastica = data["pyelastica"]
elasticapp_naive = data["elasticapp_naive"]
elasticapp_blaze = data["elasticapp_blaze"]
elasticapp_blaze_copy = data["elasticapp_blaze_copy"]
elasticapp_blaze_final = data["elasticapp_blaze_final"]
print(f"{size = }")
print(f"{pyelastica = }")
print(f"{elasticapp_naive = }, ratio: {elasticapp_naive / pyelastica}")
print(f"{elasticapp_blaze = }, ratio: {elasticapp_blaze / pyelastica}")
print(f"{elasticapp_blaze_copy = }, ratio: {elasticapp_blaze_copy / pyelastica}")
print(f"{elasticapp_blaze_final = }, ratio: {elasticapp_blaze_final / pyelastica}")
print()
Loading

0 comments on commit 85ddf84

Please sign in to comment.