Skip to content

Commit c795ef3

Browse files
committed
adding windows instructions and some small refactor as per reviews
1 parent 573eb76 commit c795ef3

File tree

5 files changed

+202
-117
lines changed

5 files changed

+202
-117
lines changed

quaddtype/README.md

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ np.array([1,2,3], dtype=QuadPrecDType("longdouble"))
2525

2626
## Installation from source
2727

28-
The code needs the quad precision pieces of the sleef library, which
29-
is not available on most systems by default, so we have to generate
30-
that first. The below assumes one has the required pieces to build
31-
sleef (cmake and libmpfr-dev), and that one is in the package
32-
directory locally.
28+
The code needs the quad precision pieces of the sleef library, which is not available on most systems by default, so we have to generate that first. Choose the appropriate section below based on your operating system.
29+
30+
### Linux/Unix/macOS
31+
32+
The below assumes one has the required pieces to build sleef (cmake and libmpfr-dev), and that one is in the package directory locally.
3333

3434
```bash
3535
git clone --branch 3.8 https://github.com/shibatch/sleef.git
@@ -68,3 +68,91 @@ python -m pip install . -v --no-build-isolation -Cbuilddir=build -C'compile-args
6868
cd ..
6969
python -m pytest
7070
```
71+
72+
### Windows
73+
74+
#### Prerequisites
75+
76+
- **Visual Studio 2017 or later** (with MSVC compiler)
77+
- **CMake** (≥3.15)
78+
- **Python 3.10+**
79+
- **Git**
80+
81+
#### Step-by-Step Installation
82+
83+
1. **Setup Development Environment**
84+
85+
Open a **Developer Command Prompt for VS** or **Developer PowerShell for VS** to ensure MSVC is properly configured.
86+
87+
2. **Clone and Build SLEEF**
88+
89+
```powershell
90+
# Clone SLEEF library
91+
git clone --branch 3.8 https://github.com/shibatch/sleef.git
92+
cd sleef
93+
94+
# Configure with CMake for Windows
95+
cmake -S . -B build -G "Visual Studio 17 2022" -A x64 -DSLEEF_BUILD_QUAD:BOOL=ON -DSLEEF_BUILD_SHARED_LIBS:BOOL=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON
96+
97+
# Build and install SLEEF
98+
cmake --build build --config Release
99+
cmake --install build --prefix "C:/sleef" --config Release
100+
101+
cd ..
102+
```
103+
104+
3. **Setup Python Environment**
105+
106+
```powershell
107+
# Create and activate virtual environment
108+
python -m venv numpy_quad_env
109+
.\numpy_quad_env\Scripts\Activate.ps1
110+
111+
# Install build dependencies
112+
pip install -U pip
113+
pip install meson-python numpy pytest ninja meson
114+
```
115+
116+
4. **Set Environment Variables**
117+
118+
```powershell
119+
# Set up paths and compiler flags
120+
$env:INCLUDE = "C:/sleef/include;$env:INCLUDE"
121+
$env:LIB = "C:/sleef/lib;$env:LIB"
122+
$env:PATH = "C:/sleef/bin;$env:PATH"
123+
124+
# Note: QBLAS is disabled on Windows due to MSVC compatibility issues
125+
$env:CFLAGS = "/IC:/sleef/include /DDISABLE_QUADBLAS"
126+
$env:CXXFLAGS = "/IC:/sleef/include /DDISABLE_QUADBLAS"
127+
$env:LDFLAGS = "C:/sleef/lib/sleef.lib C:/sleef/lib/sleefquad.lib"
128+
```
129+
130+
5. **Build and Install numpy-quaddtype**
131+
132+
```powershell
133+
# Ensure submodules are initialized
134+
git submodule update --init --recursive
135+
136+
# Build and install the package
137+
python -m pip install . -v --no-build-isolation -Cbuilddir=build -C'compile-args=-v'
138+
```
139+
140+
6. **Test Installation**
141+
142+
```powershell
143+
# Run tests
144+
pytest -s tests/
145+
```
146+
147+
1. **QBLAS Disabled**: QuadBLAS optimization is automatically disabled on Windows builds due to MSVC compatibility issues. This is handled by the `-DDISABLE_QUADBLAS` compiler flag.
148+
149+
2. **Visual Studio Version**: The instructions assume Visual Studio 2022. For other versions, adjust the generator string:
150+
- VS 2019: `"Visual Studio 16 2019"`
151+
- VS 2017: `"Visual Studio 15 2017"`
152+
153+
3. **Architecture**: The instructions are for x64. For x86 builds, change `-A x64` to `-A Win32`.
154+
155+
4. **Alternative SLEEF Location**: If you prefer to install SLEEF elsewhere, update all path references accordingly.
156+
157+
#### Windows Troubleshooting
158+
- **Link errors**: Verify that `sleef.lib` and `sleefquad.lib` exist in `C:/sleef/lib/`

quaddtype/numpy_quaddtype/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
get_quadblas_version
99
)
1010

11-
import multiprocessing
12-
1311
__all__ = [
1412
'QuadPrecision', 'QuadPrecDType', 'SleefQuadPrecision', 'LongDoubleQuadPrecision',
1513
'SleefQuadPrecDType', 'LongDoubleQuadPrecDType', 'is_longdouble_128',

quaddtype/numpy_quaddtype/src/umath/matmul.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ quad_matmul_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[
3636
if (descr_in1->backend != BACKEND_SLEEF || descr_in2->backend != BACKEND_SLEEF) {
3737
PyErr_SetString(PyExc_NotImplementedError,
3838
"QBLAS-accelerated matmul only supports SLEEF backend. "
39-
"Other backends are not supported with QBLAS.");
39+
"Please raise the issue at SwayamInSync/QBLAS for longdouble support");
4040
return (NPY_CASTING)-1;
4141
}
4242

@@ -61,7 +61,8 @@ quad_matmul_resolve_descriptors(PyObject *self, PyArray_DTypeMeta *const dtypes[
6161
QuadPrecDTypeObject *descr_out = (QuadPrecDTypeObject *)given_descrs[2];
6262
if (descr_out->backend != target_backend) {
6363
PyErr_SetString(PyExc_NotImplementedError,
64-
"QBLAS-accelerated matmul only supports SLEEF backend for output.");
64+
"QBLAS-accelerated matmul only supports SLEEF backend. "
65+
"Please raise the issue at SwayamInSync/QBLAS for longdouble support");
6566
return (NPY_CASTING)-1;
6667
}
6768
else {
@@ -118,7 +119,9 @@ quad_matmul_strided_loop_aligned(PyArrayMethod_Context *context, char *const dat
118119

119120
QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)context->descriptors[0];
120121
if (descr->backend != BACKEND_SLEEF) {
121-
PyErr_SetString(PyExc_RuntimeError, "Internal error: non-SLEEF backend in QBLAS matmul");
122+
PyErr_SetString(PyExc_NotImplementedError,
123+
"QBLAS-accelerated matmul only supports SLEEF backend. "
124+
"Please raise the issue at SwayamInSync/QBLAS for longdouble support");
122125
return -1;
123126
}
124127

@@ -206,7 +209,9 @@ quad_matmul_strided_loop_unaligned(PyArrayMethod_Context *context, char *const d
206209

207210
QuadPrecDTypeObject *descr = (QuadPrecDTypeObject *)context->descriptors[0];
208211
if (descr->backend != BACKEND_SLEEF) {
209-
PyErr_SetString(PyExc_RuntimeError, "Internal error: non-SLEEF backend in QBLAS matmul");
212+
PyErr_SetString(PyExc_NotImplementedError,
213+
"QBLAS-accelerated matmul only supports SLEEF backend. "
214+
"Please raise the issue at SwayamInSync/QBLAS for longdouble support");
210215
return -1;
211216
}
212217

quaddtype/tests/test_dot.py

Lines changed: 2 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,9 @@
11
import pytest
22
import numpy as np
3+
from test_utils import create_quad_array, assert_quad_equal, assert_quad_array_equal, arrays_equal_with_nan
34
from numpy_quaddtype import QuadPrecision, QuadPrecDType
45

56

6-
# ================================================================================
7-
# UTILITIES
8-
# ================================================================================
9-
10-
def assert_quad_equal(a, b, rtol=1e-15, atol=1e-15):
11-
"""Assert two quad precision values are equal within tolerance"""
12-
# Ensure both operands are QuadPrecision objects for the comparison
13-
if not isinstance(a, QuadPrecision):
14-
a = QuadPrecision(str(a), backend='sleef')
15-
if not isinstance(b, QuadPrecision):
16-
b = QuadPrecision(str(b), backend='sleef')
17-
18-
# Use quad-precision arithmetic to calculate the difference
19-
diff = abs(a - b)
20-
tolerance = QuadPrecision(str(atol), backend='sleef') + QuadPrecision(str(rtol), backend='sleef') * max(abs(a), abs(b))
21-
22-
# Assert using quad-precision objects
23-
assert diff <= tolerance, f"Values not equal: {a} != {b} (diff: {diff}, tol: {tolerance})"
24-
25-
26-
def assert_quad_array_equal(a, b, rtol=1e-25, atol=1e-25):
27-
"""Assert two quad precision arrays are equal within tolerance"""
28-
assert a.shape == b.shape, f"Shapes don't match: {a.shape} vs {b.shape}"
29-
30-
flat_a = a.flatten()
31-
flat_b = b.flatten()
32-
33-
for i, (val_a, val_b) in enumerate(zip(flat_a, flat_b)):
34-
try:
35-
assert_quad_equal(val_a, val_b, rtol, atol)
36-
except AssertionError as e:
37-
raise AssertionError(f"Arrays differ at index {i}: {e}")
38-
39-
40-
def create_quad_array(values, shape=None):
41-
"""Create a QuadPrecision array from values using Sleef backend"""
42-
dtype = QuadPrecDType(backend='sleef')
43-
44-
if isinstance(values, (list, tuple)):
45-
if shape is None:
46-
# 1D array
47-
quad_values = [QuadPrecision(str(float(v)), backend='sleef') for v in values]
48-
return np.array(quad_values, dtype=dtype)
49-
else:
50-
# Reshape to specified shape
51-
if len(shape) == 1:
52-
quad_values = [QuadPrecision(str(float(v)), backend='sleef') for v in values]
53-
return np.array(quad_values, dtype=dtype)
54-
elif len(shape) == 2:
55-
m, n = shape
56-
assert len(values) == m * n, f"Values length {len(values)} doesn't match shape {shape}"
57-
quad_matrix = []
58-
for i in range(m):
59-
row = [QuadPrecision(str(float(values[i * n + j])), backend='sleef') for j in range(n)]
60-
quad_matrix.append(row)
61-
return np.array(quad_matrix, dtype=dtype)
62-
63-
raise ValueError("Unsupported values or shape")
64-
65-
66-
def is_special_value(val):
67-
"""Check if a value is NaN or infinite"""
68-
try:
69-
float_val = float(val)
70-
return np.isnan(float_val) or np.isinf(float_val)
71-
except:
72-
return False
73-
74-
75-
def arrays_equal_with_nan(a, b, rtol=1e-15, atol=1e-15):
76-
"""Compare arrays that may contain NaN values"""
77-
if a.shape != b.shape:
78-
return False
79-
80-
flat_a = a.flatten()
81-
flat_b = b.flatten()
82-
83-
for i, (val_a, val_b) in enumerate(zip(flat_a, flat_b)):
84-
# Handle NaN cases
85-
if is_special_value(val_a) and is_special_value(val_b):
86-
float_a = float(val_a)
87-
float_b = float(val_b)
88-
# Both NaN
89-
if np.isnan(float_a) and np.isnan(float_b):
90-
continue
91-
# Both infinite with same sign
92-
elif np.isinf(float_a) and np.isinf(float_b) and np.sign(float_a) == np.sign(float_b):
93-
continue
94-
else:
95-
return False
96-
elif is_special_value(val_a) or is_special_value(val_b):
97-
return False
98-
else:
99-
try:
100-
assert_quad_equal(val_a, val_b, rtol, atol)
101-
except AssertionError:
102-
return False
103-
104-
return True
105-
106-
1077
# ================================================================================
1088
# VECTOR-VECTOR DOT PRODUCT TESTS
1099
# ================================================================================
@@ -789,8 +689,4 @@ def test_dimension_mismatch_matrices(self):
789689
B = create_quad_array([1, 2, 3, 4, 5, 6], shape=(3, 2)) # Wrong size
790690

791691
with pytest.raises(ValueError, match=r"matmul: Input operand 1 has a mismatch in its core dimension 0"):
792-
np.matmul(A, B)
793-
794-
795-
if __name__ == "__main__":
796-
pytest.main([__file__, "-v"])
692+
np.matmul(A, B)

quaddtype/tests/test_utils.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from numpy_quaddtype import QuadPrecision, QuadPrecDType
2+
import numpy as np
3+
4+
def assert_quad_equal(a, b, rtol=1e-15, atol=1e-15):
5+
"""Assert two quad precision values are equal within tolerance"""
6+
# Ensure both operands are QuadPrecision objects for the comparison
7+
if not isinstance(a, QuadPrecision):
8+
a = QuadPrecision(str(a), backend='sleef')
9+
if not isinstance(b, QuadPrecision):
10+
b = QuadPrecision(str(b), backend='sleef')
11+
12+
# Use quad-precision arithmetic to calculate the difference
13+
diff = abs(a - b)
14+
tolerance = QuadPrecision(str(atol), backend='sleef') + QuadPrecision(str(rtol), backend='sleef') * max(abs(a), abs(b))
15+
16+
# Assert using quad-precision objects
17+
assert diff <= tolerance, f"Values not equal: {a} != {b} (diff: {diff}, tol: {tolerance})"
18+
19+
20+
def assert_quad_array_equal(a, b, rtol=1e-25, atol=1e-25):
21+
"""Assert two quad precision arrays are equal within tolerance"""
22+
assert a.shape == b.shape, f"Shapes don't match: {a.shape} vs {b.shape}"
23+
24+
flat_a = a.flatten()
25+
flat_b = b.flatten()
26+
27+
for i, (val_a, val_b) in enumerate(zip(flat_a, flat_b)):
28+
try:
29+
assert_quad_equal(val_a, val_b, rtol, atol)
30+
except AssertionError as e:
31+
raise AssertionError(f"Arrays differ at index {i}: {e}")
32+
33+
34+
def create_quad_array(values, shape=None):
35+
"""Create a QuadPrecision array from values using Sleef backend"""
36+
dtype = QuadPrecDType(backend='sleef')
37+
38+
if isinstance(values, (list, tuple)):
39+
if shape is None:
40+
# 1D array
41+
quad_values = [QuadPrecision(str(float(v)), backend='sleef') for v in values]
42+
return np.array(quad_values, dtype=dtype)
43+
else:
44+
# Reshape to specified shape
45+
if len(shape) == 1:
46+
quad_values = [QuadPrecision(str(float(v)), backend='sleef') for v in values]
47+
return np.array(quad_values, dtype=dtype)
48+
elif len(shape) == 2:
49+
m, n = shape
50+
assert len(values) == m * n, f"Values length {len(values)} doesn't match shape {shape}"
51+
quad_matrix = []
52+
for i in range(m):
53+
row = [QuadPrecision(str(float(values[i * n + j])), backend='sleef') for j in range(n)]
54+
quad_matrix.append(row)
55+
return np.array(quad_matrix, dtype=dtype)
56+
57+
raise ValueError("Unsupported values or shape")
58+
59+
60+
def is_special_value(val):
61+
"""Check if a value is NaN or infinite"""
62+
try:
63+
float_val = float(val)
64+
return np.isnan(float_val) or np.isinf(float_val)
65+
except:
66+
return False
67+
68+
69+
def arrays_equal_with_nan(a, b, rtol=1e-15, atol=1e-15):
70+
"""Compare arrays that may contain NaN values"""
71+
if a.shape != b.shape:
72+
return False
73+
74+
flat_a = a.flatten()
75+
flat_b = b.flatten()
76+
77+
for i, (val_a, val_b) in enumerate(zip(flat_a, flat_b)):
78+
# Handle NaN cases
79+
if is_special_value(val_a) and is_special_value(val_b):
80+
float_a = float(val_a)
81+
float_b = float(val_b)
82+
# Both NaN
83+
if np.isnan(float_a) and np.isnan(float_b):
84+
continue
85+
# Both infinite with same sign
86+
elif np.isinf(float_a) and np.isinf(float_b) and np.sign(float_a) == np.sign(float_b):
87+
continue
88+
else:
89+
return False
90+
elif is_special_value(val_a) or is_special_value(val_b):
91+
return False
92+
else:
93+
try:
94+
assert_quad_equal(val_a, val_b, rtol, atol)
95+
except AssertionError:
96+
return False
97+
98+
return True

0 commit comments

Comments
 (0)