Skip to content

Commit f054c32

Browse files
authored
Merge pull request #24 from tohtsky/develop
MSVC wheel (#23)
2 parents e711be6 + a2deba8 commit f054c32

File tree

7 files changed

+168
-154
lines changed

7 files changed

+168
-154
lines changed

.github/workflows/wheels.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ on:
33
push:
44
branches:
55
- main
6+
- develop
67
release:
78
types:
89
- created
@@ -28,7 +29,7 @@ jobs:
2829
runs-on: ${{ matrix.os }}
2930
strategy:
3031
matrix:
31-
os: [ubuntu-20.04, macOS-10.15]
32+
os: [ubuntu-20.04, macOS-10.15, windows-2019]
3233

3334
steps:
3435
- uses: actions/checkout@v2
@@ -43,7 +44,7 @@ jobs:
4344
run: python -m cibuildwheel --output-dir wheelhouse
4445
env:
4546
CIBW_BUILD: "cp36-* cp37-* cp38-* cp39-*"
46-
CIBW_ENVIRONMENT: "CFLAGS='-march=core-avx-i' CXXFLAGS='-march=core-avx-i'"
47+
CIBW_ENVIRONMENT: "CFLAGS='-march=core-avx-i' CXXFLAGS='-march=core-avx-i' CL='/arch:AVX'"
4748
CIBW_TEST_COMMAND: pytest {project}/tests
4849
CIBW_TEST_REQUIRES: pytest
4950

Readme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ However, I decided to implement my own one to
2323

2424
# Installation & Optional Dependencies
2525

26-
There are binaries for Linux & MacOS with python>=3.6. You can install them via
26+
There are binaries for Linux, MacOS, and Windows with python>=3.6. You can install them via
2727

2828
```sh
2929
pip install irspack
3030
```
3131

32-
The binary has been compiled to use AVX instruction. If you want to use AVX2/AVX512 or your environment does not support AVX, install it from source like
32+
The binaries have been compiled to use AVX instruction. If you want to use AVX2/AVX512 or your environment does not support AVX, install it from source like
3333

3434
```sh
3535
CFLAGS="-march=native" pip install git+https://github.com/tohtsky/irspack.git

cpp_source/als/wrapper.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <pybind11/eigen.h>
77
#include <pybind11/pybind11.h>
88
#include <pybind11/stl.h>
9+
#include <sstream>
910
#include <stdexcept>
1011
#include <vector>
1112

@@ -14,8 +15,12 @@ using namespace ials11;
1415
using std::vector;
1516

1617
PYBIND11_MODULE(_ials, m) {
17-
py::print("info: irspack's _ials core built to use\n\t",
18-
Eigen::SimdInstructionSetsInUse());
18+
std::stringstream doc_stream;
19+
doc_stream << "irspack's core module for \"IALSRecommender\"." << std::endl
20+
<< "Built to use" << std::endl
21+
<< "\t" << Eigen::SimdInstructionSetsInUse();
22+
23+
m.doc() = doc_stream.str();
1924
py::class_<IALSLearningConfig>(m, "IALSLearningConfig")
2025
.def(py::init<size_t, Real, Real, Real, int, size_t, bool, size_t>())
2126
.def(py::pickle(

cpp_source/evaluator.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ namespace irspack {
2222

2323
using CountVector = Eigen::Matrix<std::int64_t, Eigen::Dynamic, 1>;
2424
struct Metrics {
25+
// This isn't necessary, but MSVC complains Metric is not default
26+
// constructible.
27+
inline Metrics() : Metrics(0) {}
2528
inline Metrics(size_t n_item) : n_item(n_item), item_cnt(n_item) {
2629
item_cnt.array() = 0;
2730
}

tests/dataset/test_ml100k.py

Lines changed: 0 additions & 67 deletions
This file was deleted.

tests/dataset/test_ml1m.py

Lines changed: 153 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,161 @@
1-
from tempfile import NamedTemporaryFile
1+
import os
2+
import sys
23
from zipfile import ZipFile
34

45
import numpy as np
6+
import pytest
57

6-
from irspack.dataset.movielens import MovieLens1MDataManager
8+
from irspack.dataset.movielens import (
9+
MovieLens1MDataManager,
10+
MovieLens20MDataManager,
11+
MovieLens100KDataManager,
12+
)
13+
14+
ZIPFILE_NAME = os.path.join(os.path.expanduser("~"), "ml.test.zip")
15+
16+
17+
def test_ml100k() -> None:
18+
if sys.platform == "win32":
19+
pytest.skip("Skip on Windows.")
20+
GENRES = ["fantasy", "action", "thriller"]
21+
try:
22+
with ZipFile(ZIPFILE_NAME, "w") as zf:
23+
with zf.open("ml-100k/u.data", "w") as ofs:
24+
ofs.write("1\t2\t5\t0\n1\t3\t5\t86400".encode())
25+
26+
with zf.open("ml-100k/u.genre", "w") as ofs:
27+
genre_string = ""
28+
for i, genre in enumerate(GENRES):
29+
genre_string += f"{genre}|{i}\n"
30+
ofs.write(genre_string.encode())
31+
32+
with zf.open("ml-100k/u.item", "w") as ofs:
33+
# movieId = 1 has action tag,
34+
# movieId = 2 has fantasy & thriller tags
35+
ofs.write(
36+
"""1|A fantastic movie|2020-01-01|2021-01-01|http://example.com|0|1|0
37+
2|Pandemic|2020-01-01|2021-01-01|http://example.com|1|0|1""".encode(
38+
"latin-1"
39+
)
40+
)
41+
with zf.open("ml-100k/u.user", "w") as ofs:
42+
ofs.write(
43+
"""1|32|M|0|1690074
44+
2|4|F|1|1760013
45+
""".encode()
46+
)
47+
48+
loader = MovieLens100KDataManager(ZIPFILE_NAME)
49+
df = loader.read_interaction()
50+
movie_info, genres = loader.read_item_info()
51+
user_info = loader.read_user_info()
52+
assert df.shape == (2, 4)
53+
np.testing.assert_array_equal(df["userId"].values, [1, 1])
54+
np.testing.assert_array_equal(df["movieId"].values, [2, 3])
55+
np.testing.assert_array_equal(df["rating"].values, [5, 5])
56+
np.testing.assert_array_equal(
57+
df["timestamp"].values,
58+
np.asarray(
59+
[
60+
"1970-01-01",
61+
"1970-01-02",
62+
],
63+
dtype="datetime64[ns]",
64+
),
65+
)
66+
np.testing.assert_array_equal(movie_info.index.values, [1, 2])
67+
np.testing.assert_array_equal(
68+
movie_info.release_date,
69+
np.asarray(["2020-01-01", "2020-01-01"], dtype="datetime64[ns]"),
70+
)
71+
assert set(genres[genres.movieId == 1].genre) == set(["action"])
72+
assert set(genres[genres.movieId == 2].genre) == set(["fantasy", "thriller"])
73+
74+
np.testing.assert_array_equal(user_info.index.values, [1, 2])
75+
np.testing.assert_array_equal(user_info.gender, ["M", "F"])
76+
finally:
77+
os.remove(ZIPFILE_NAME)
778

879

980
def test_ml1m() -> None:
10-
fp = NamedTemporaryFile("wb")
11-
fp.name
12-
with ZipFile(fp.name, "w") as zf:
13-
with zf.open("ml-1m/ratings.dat", "w") as ofs:
14-
ofs.write(
15-
"""1::2::5::0
16-
1::3::5::86400
17-
""".encode()
18-
)
19-
with zf.open("ml-1m/movies.dat", "w") as ofs:
20-
ofs.write(
21-
"""1::A fantastic movie (2020)::fantasy|thriller
22-
1917::Vinni-Pukh(1969)::children
23-
""".encode(
24-
"latin-1"
81+
if sys.platform == "win32":
82+
pytest.skip("Skip on Windows.")
83+
84+
try:
85+
with ZipFile(ZIPFILE_NAME, "w") as zf:
86+
with zf.open("ml-1m/ratings.dat", "w") as ofs:
87+
ofs.write(
88+
"""1::2::5::0
89+
1::3::5::86400
90+
""".encode()
91+
)
92+
with zf.open("ml-1m/movies.dat", "w") as ofs:
93+
ofs.write(
94+
"""1::A fantastic movie (2020)::fantasy|thriller
95+
1917::Vinni-Pukh(1969)::children
96+
""".encode(
97+
"latin-1"
98+
)
99+
)
100+
with zf.open("ml-1m/users.dat", "w") as ofs:
101+
ofs.write(
102+
"""1::M::32::0::1690074
103+
2::F::4::1::1760013
104+
""".encode()
105+
)
106+
107+
loader = MovieLens1MDataManager(ZIPFILE_NAME)
108+
df = loader.read_interaction()
109+
movie_info = loader.read_item_info()
110+
user_info = loader.read_user_info()
111+
assert df.shape == (2, 4)
112+
np.testing.assert_array_equal(df["userId"].values, [1, 1])
113+
np.testing.assert_array_equal(df["movieId"].values, [2, 3])
114+
np.testing.assert_array_equal(df["rating"].values, [5, 5])
115+
np.testing.assert_array_equal(
116+
df["timestamp"].values,
117+
np.asarray(
118+
[
119+
"1970-01-01",
120+
"1970-01-02",
121+
],
122+
dtype="datetime64[ns]",
123+
),
124+
)
125+
np.testing.assert_array_equal(movie_info.index.values, [1, 1917])
126+
np.testing.assert_array_equal(movie_info.release_year, [2020, 1969])
127+
np.testing.assert_array_equal(user_info.index.values, [1, 2])
128+
np.testing.assert_array_equal(user_info.gender, ["M", "F"])
129+
finally:
130+
os.remove(ZIPFILE_NAME)
131+
132+
133+
def test_ml20m() -> None:
134+
if sys.platform == "win32":
135+
pytest.skip("Skip on Windows.")
136+
try:
137+
with ZipFile(ZIPFILE_NAME, "w") as zf:
138+
with zf.open("ml-20m/ratings.csv", "w") as ofs:
139+
ofs.write(
140+
"""userId,movieId,rating,timestamp
141+
1,2,5,0
142+
1,3,5,86400
143+
""".encode()
25144
)
26-
)
27-
with zf.open("ml-1m/users.dat", "w") as ofs:
28-
ofs.write(
29-
"""1::M::32::0::1690074
30-
2::F::4::1::1760013
31-
""".encode()
32-
)
33-
34-
loader = MovieLens1MDataManager(fp.name)
35-
df = loader.read_interaction()
36-
movie_info = loader.read_item_info()
37-
user_info = loader.read_user_info()
38-
assert df.shape == (2, 4)
39-
np.testing.assert_array_equal(df["userId"].values, [1, 1])
40-
np.testing.assert_array_equal(df["movieId"].values, [2, 3])
41-
np.testing.assert_array_equal(df["rating"].values, [5, 5])
42-
np.testing.assert_array_equal(
43-
df["timestamp"].values,
44-
np.asarray(
45-
[
46-
"1970-01-01",
47-
"1970-01-02",
48-
],
49-
dtype="datetime64[ns]",
50-
),
51-
)
52-
np.testing.assert_array_equal(movie_info.index.values, [1, 1917])
53-
np.testing.assert_array_equal(movie_info.release_year, [2020, 1969])
54-
np.testing.assert_array_equal(user_info.index.values, [1, 2])
55-
np.testing.assert_array_equal(user_info.gender, ["M", "F"])
145+
loader = MovieLens20MDataManager(ZIPFILE_NAME)
146+
df = loader.read_interaction()
147+
np.testing.assert_array_equal(df["userId"].values, [1, 1])
148+
np.testing.assert_array_equal(df["movieId"].values, [2, 3])
149+
np.testing.assert_array_equal(df["rating"].values, [5, 5])
150+
np.testing.assert_array_equal(
151+
df["timestamp"].values,
152+
np.asarray(
153+
[
154+
"1970-01-01",
155+
"1970-01-02",
156+
],
157+
dtype="datetime64[ns]",
158+
),
159+
)
160+
finally:
161+
os.remove(ZIPFILE_NAME)

tests/dataset/test_ml20m.py

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)