Skip to content
This repository was archived by the owner on Jan 26, 2026. It is now read-only.

Commit 030678e

Browse files
committed
Using cmake to allow parallel and incremental builds, adding min and max
1 parent 3146a1e commit 030678e

14 files changed

Lines changed: 788 additions & 668 deletions

File tree

CMakeLists.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
cmake_minimum_required(VERSION 3.18.2)
2+
project(ddptensor VERSION 1.0)
3+
4+
# C++ standard
5+
set(CMAKE_CXX_STANDARD 17)
6+
set(CMAKE_C_EXTENSIONS OFF)
7+
set(CMAKE_CXX_EXTENSIONS OFF)
8+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
9+
10+
# Common installation directories
11+
#include(GNUInstallDirs)
12+
13+
# Use -fPIC even if statically compiled
14+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
15+
16+
# ============
17+
# Target
18+
# ============
19+
FILE(GLOB MyCppSources ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/include/ddptensor/*.hpp)
20+
21+
# Create the mymath library
22+
add_library(_ddptensor SHARED ${MyCppSources})
23+
24+
target_include_directories(_ddptensor PRIVATE ${PROJECT_SOURCE_DIR}/src/include ${PROJECT_SOURCE_DIR}/third_party/xtl/include ${PROJECT_SOURCE_DIR}/third_party/xsimd/include ${PROJECT_SOURCE_DIR}/third_party/xtensor-blas/include ${PROJECT_SOURCE_DIR}/third_party/xtensor/include ${PROJECT_SOURCE_DIR}/third_party/bitsery/include)
25+
26+
# ===============
27+
# Deps
28+
# ===============
29+
30+
# Find Python3 and NumPy
31+
find_package(Python3 COMPONENTS Interpreter Development.Module NumPy REQUIRED)
32+
33+
find_package(MPI REQUIRED)
34+
find_package(pybind11 CONFIG)
35+
include_directories(SYSTEM ${MPI_INCLUDE_PATH} ${pybind11_INCLUDE_DIRS})
36+
target_link_libraries(_ddptensor ${MPI_C_LIBRARIES})

ddptensor/__init__.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1+
"""
2+
Distributed implementation of the array API as defined here:
3+
https://data-apis.org/array-api/latest
4+
"""
5+
6+
# Many features of the API are very uniformly defined.
7+
# We make use of that by providing lists of operations which are similar
8+
# (see array_api.py). __init__.py and ddptensor.py simply generate the API
9+
# by iterating through these lists and forwarding the function calls the the
10+
# C++-extension. Python functions are defined and added by using "eval".
11+
# For many operations we assume the C++-extension defines enums which allow
12+
# us identifying each operation.
13+
# At this point there are no checks of input arguments whatsoever, arguments
14+
# are simply forwarded as-is.
15+
116
from . import _ddptensor as _cdt
217
from .ddptensor import float64, int64, fini, dtensor
318
from os import getenv
419
from . import array_api as api
520
from . import spmd
621

7-
#__impl_str = getenv("DDPNP_ARRAY", 'numpy')
8-
#exec(f"import {__impl_str} as __impl")
9-
1022
for op in api.ew_binary_ops:
1123
OP = op.upper()
1224
exec(

ddptensor/array_api.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""
2+
The list of data API operations for ddptensor, a
3+
distributed implementation of the array API as defined here:
4+
https://data-apis.org/array-api/latest
5+
"""
6+
17
creators = [
28
"arange", # (start, /, stop=None, step=1, *, dtype=None, device=None)
39
"asarray", # (obj, /, *, dtype=None, device=None, copy=None)

ddptensor/ddptensor.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1+
"""
2+
The Tensor class for ddptensor, a
3+
distributed implementation of the array API as defined here:
4+
https://data-apis.org/array-api/latest
5+
"""
6+
#
7+
# See __init__.py for an implementation overview
8+
#
19
from . import _ddptensor as _cdt
210
from ._ddptensor import float64, int64, fini
311
from . import array_api as api
412

5-
#def try_except(func, *args, **kwargs):
6-
# try:
7-
# return func(*args, **kwargs)
8-
# except:
9-
# return None
10-
1113
class dtensor:
1214
def __init__(self, t):
1315
self._t = t

setup.py

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,39 @@
1-
import os
2-
from os.path import join as jp
3-
from glob import glob
1+
import cmake_build_extension
42
from setuptools import setup
5-
from pybind11.setup_helpers import Pybind11Extension
6-
7-
mpiroot = os.environ.get('MPIROOT')
8-
mklroot = os.environ.get('MKLROOT')
9-
xtroot = os.getenv('XTROOT', 'third_party')
10-
11-
xt_includes = [jp(xtroot, x, "include") for x in ("xtl", "xsimd", "xtensor-blas", "xtensor")]
3+
from pathlib import Path
124

135
ext_modules = [
14-
Pybind11Extension(
15-
"ddptensor._ddptensor",
16-
glob("src/*.cpp"),
17-
include_dirs = xt_includes + [jp(mpiroot, "include"), jp("third_party", "bitsery", "include"), jp("src", "include"), ],
18-
extra_compile_args = ["-DUSE_MKL", "-DXTENSOR_USE_XSIMD=1", "-DXTENSOR_USE_OPENMP=1",
19-
"-std=c++17", "-fopenmp",
20-
"-Wno-unused-but-set-variable", "-Wno-sign-compare", "-Wno-unused-local-typedefs", "-Wno-reorder",
21-
"-march=native", "-O0", "-g"],
22-
libraries = ["mpi", "mkl_intel_lp64", "mkl_intel_thread", "mkl_core", "iomp5", "pthread", "rt", "dl", "m"],
23-
library_dirs = [jp(mpiroot, "lib")],
24-
language = 'c++'
25-
),
26-
]
6+
cmake_build_extension.CMakeExtension(
7+
name="_ddptensor",
8+
# Name of the resulting package name (import mymath_pybind11)
9+
install_prefix="ddptensor",
10+
# Note: pybind11 is a build-system requirement specified in pyproject.toml,
11+
# therefore pypa/pip or pypa/build will install it in the virtual
12+
# environment created in /tmp during packaging.
13+
# This cmake_depends_on option adds the pybind11 installation path
14+
# to CMAKE_PREFIX_PATH so that the example finds the pybind11 targets
15+
# even if it is not installed in the system.
16+
cmake_depends_on=["pybind11"],
17+
# Exposes the binary print_answer to the environment.
18+
# It requires also adding a new entry point in setup.cfg.
19+
# expose_binaries=["bin/print_answer"],
20+
# Writes the content to the top-level __init__.py
21+
#write_top_level_init=init_py,
22+
# Selects the folder where the main CMakeLists.txt is stored
23+
# (it could be a subfolder)
24+
source_dir=str(Path(__file__).parent.absolute()),
25+
cmake_configure_options=[
26+
]
27+
),
28+
]
2729

2830
setup(name="ddptensor",
2931
version="0.1",
3032
description="Distributed Tensor and more",
3133
packages=["ddptensor", "ddptensor.numpy", "ddptensor.torch"],
32-
ext_modules=ext_modules
34+
ext_modules=ext_modules,
35+
cmdclass=dict(
36+
# Enable the CMakeExtension entries defined above
37+
build_ext=cmake_build_extension.BuildExtension,
38+
),
3339
)

src/Creator.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include "ddptensor/Operations.hpp"
2+
#include "ddptensor/x.hpp"
3+
4+
namespace x {
5+
6+
template<typename T>
7+
class Creator
8+
{
9+
public:
10+
using ptr_type = DPTensorBaseX::ptr_type;
11+
12+
static ptr_type op(CreatorId c, shape_type && shp)
13+
{
14+
PVSlice pvslice(std::forward<shape_type>(shp));
15+
shape_type shape(std::move(pvslice.tile_shape()));
16+
switch(c) {
17+
case EMPTY:
18+
return operatorx<T>::mk_tx(std::move(pvslice), std::move(xt::empty<T>(shape)));
19+
case ONES:
20+
return operatorx<T>::mk_tx(std::move(pvslice), std::move(xt::ones<T>(shape)));
21+
case ZEROS:
22+
return operatorx<T>::mk_tx(std::move(pvslice), std::move(xt::zeros<T>(shape)));
23+
default:
24+
throw std::runtime_error("Unknown creator");
25+
};
26+
};
27+
28+
template<typename V>
29+
static ptr_type op(CreatorId c, shape_type && shp, V && v)
30+
{
31+
if(c == FULL) {
32+
PVSlice pvslice(std::forward<shape_type>(shp));
33+
shape_type shape(std::move(pvslice.tile_shape()));
34+
auto a = xt::empty<T>(std::move(shape));
35+
a.fill(to_native<T>(v));
36+
return operatorx<T>::mk_tx(std::move(pvslice), std::move(a));
37+
}
38+
throw std::runtime_error("Unknown creator");
39+
}
40+
}; // class creatorx
41+
} // namespace x
42+
43+
tensor_i::ptr_type Creator::create_from_shape(CreatorId op, shape_type && shape, DType dtype)
44+
{
45+
return TypeDispatch<x::Creator>(dtype, op, std::forward<shape_type>(shape));
46+
}
47+
48+
tensor_i::ptr_type Creator::full(shape_type && shape, py::object && val, DType dtype)
49+
{
50+
auto op = FULL;
51+
return TypeDispatch<x::Creator>(dtype, op, std::forward<shape_type>(shape), std::forward<py::object>(val));
52+
}

src/EWBinOp.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include "ddptensor/Operations.hpp"
2+
#include "ddptensor/x.hpp"
3+
4+
namespace x {
5+
6+
template<typename T>
7+
class EWBinOp
8+
{
9+
public:
10+
using ptr_type = DPTensorBaseX::ptr_type;
11+
12+
#pragma GCC diagnostic ignored "-Wswitch"
13+
14+
template<typename A, typename B, typename U = T, std::enable_if_t<std::is_floating_point<U>::value, bool> = true>
15+
static ptr_type integral_op(EWBinOpId iop, const DPTensorX<T> & tx, A && a, B && b)
16+
{
17+
throw std::runtime_error("Illegal or unknown inplace elementwise binary operation");
18+
}
19+
20+
template<typename A, typename B, typename U = T, std::enable_if_t<std::is_integral<U>::value, bool> = true>
21+
static ptr_type integral_op(EWBinOpId iop, const DPTensorX<T> & tx, A && a, B && b)
22+
{
23+
switch(iop) {
24+
case __AND__:
25+
case BITWISE_AND:
26+
return operatorx<T>::mk_tx_(tx, a & b);
27+
case __RAND__:
28+
return operatorx<T>::mk_tx_(tx, b & a);
29+
case __LSHIFT__:
30+
case BITWISE_LEFT_SHIFT:
31+
return operatorx<T>::mk_tx_(tx, a << b);
32+
case __MOD__:
33+
case REMAINDER:
34+
return operatorx<T>::mk_tx_(tx, a % b);
35+
case __OR__:
36+
case BITWISE_OR:
37+
return operatorx<T>::mk_tx_(tx, a | b);
38+
case __ROR__:
39+
return operatorx<T>::mk_tx_(tx, b | a);
40+
case __RSHIFT__:
41+
case BITWISE_RIGHT_SHIFT:
42+
return operatorx<T>::mk_tx_(tx, a >> b);
43+
case __XOR__:
44+
case BITWISE_XOR:
45+
return operatorx<T>::mk_tx_(tx, a ^ b);
46+
case __RXOR__:
47+
return operatorx<T>::mk_tx_(tx, b ^ a);
48+
case __RLSHIFT__:
49+
return operatorx<T>::mk_tx_(tx, b << a);
50+
case __RMOD__:
51+
return operatorx<T>::mk_tx_(tx, b % a);
52+
case __RRSHIFT__:
53+
return operatorx<T>::mk_tx_(tx, b >> a);
54+
default:
55+
throw std::runtime_error("Unknown elementwise binary operation");
56+
}
57+
}
58+
59+
static ptr_type op(EWBinOpId bop, const ptr_type & a_ptr, const ptr_type & b_ptr)
60+
{
61+
const auto _a = dynamic_cast<DPTensorX<T>*>(a_ptr.get());
62+
const auto _b = dynamic_cast<DPTensorX<T>*>(b_ptr.get());
63+
if(!_a || !_b)
64+
throw std::runtime_error("Invalid array object: could not dynamically cast");
65+
const auto & a = xt::strided_view(_a->xarray(), _a->lslice());
66+
const auto & b = xt::strided_view(_b->xarray(), _b->lslice());
67+
68+
switch(bop) {
69+
case __ADD__:
70+
case ADD:
71+
return operatorx<T>::mk_tx_(*_a, a + b);
72+
case __RADD__:
73+
return operatorx<T>::mk_tx_(*_a, b + a);
74+
case ATAN2:
75+
return operatorx<T>::mk_tx_(*_a, xt::atan2(a, b));
76+
case __EQ__:
77+
case EQUAL:
78+
return operatorx<T>::mk_tx_(*_a, xt::equal(a, b));
79+
case __FLOORDIV__:
80+
case FLOOR_DIVIDE:
81+
return operatorx<T>::mk_tx_(*_a, xt::floor(a / b));
82+
case __GE__:
83+
case GREATER_EQUAL:
84+
return operatorx<T>::mk_tx_(*_a, a >= b);
85+
case __GT__:
86+
case GREATER:
87+
return operatorx<T>::mk_tx_(*_a, a > b);
88+
case __LE__:
89+
case LESS_EQUAL:
90+
return operatorx<T>::mk_tx_(*_a, a <= b);
91+
case __LT__:
92+
case LESS:
93+
return operatorx<T>::mk_tx_(*_a, a < b);
94+
case __MUL__:
95+
case MULTIPLY:
96+
return operatorx<T>::mk_tx_(*_a, a * b);
97+
case __RMUL__:
98+
return operatorx<T>::mk_tx_(*_a, b * a);
99+
case __NE__:
100+
case NOT_EQUAL:
101+
return operatorx<T>::mk_tx_(*_a, xt::not_equal(a, b));
102+
case __SUB__:
103+
case SUBTRACT:
104+
return operatorx<T>::mk_tx_(*_a, a - b);
105+
case __TRUEDIV__:
106+
case DIVIDE:
107+
return operatorx<T>::mk_tx_(*_a, a / b);
108+
case __RFLOORDIV__:
109+
return operatorx<T>::mk_tx_(*_a, xt::floor(b / a));
110+
case __RSUB__:
111+
return operatorx<T>::mk_tx_(*_a, b - a);
112+
case __RTRUEDIV__:
113+
return operatorx<T>::mk_tx_(*_a, b / a);
114+
case __MATMUL__:
115+
case __POW__:
116+
case POW:
117+
case __RPOW__:
118+
case LOGADDEXP:
119+
case LOGICAL_AND:
120+
case LOGICAL_OR:
121+
case LOGICAL_XOR:
122+
// FIXME
123+
throw std::runtime_error("Binary operation not implemented");
124+
}
125+
return integral_op(bop, *_a, a, b);
126+
}
127+
128+
#pragma GCC diagnostic pop
129+
130+
};
131+
} // namespace x
132+
133+
tensor_i::ptr_type EWBinOp::op(EWBinOpId op, x::DPTensorBaseX::ptr_type a, x::DPTensorBaseX::ptr_type b)
134+
{
135+
return TypeDispatch<x::EWBinOp>(a->dtype(), op, a, b);
136+
}

0 commit comments

Comments
 (0)