From 097a11704c7e3324aa1865aa4016d53bcfa01b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Thu, 13 Jun 2024 15:29:13 +0200 Subject: [PATCH 1/4] Port `read` and `write` functions --- src/finch/__init__.py | 6 ++++++ src/finch/io.py | 11 +++++++++++ src/finch/julia.py | 1 + tests/data/matrix_1.ttx | 17 +++++++++++++++++ tests/test_io.py | 25 +++++++++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 src/finch/io.py create mode 100644 tests/data/matrix_1.ttx create mode 100644 tests/test_io.py diff --git a/src/finch/__init__.py b/src/finch/__init__.py index a6e6e50..87ab562 100644 --- a/src/finch/__init__.py +++ b/src/finch/__init__.py @@ -130,6 +130,10 @@ iinfo, can_cast, ) +from .io import ( + read, + write, +) __all__ = [ "Tensor", @@ -252,6 +256,8 @@ "real", "imag", "conj", + "read", + "write", ] __array_api_version__: str = "2023.12" diff --git a/src/finch/io.py b/src/finch/io.py new file mode 100644 index 0000000..f99e8b5 --- /dev/null +++ b/src/finch/io.py @@ -0,0 +1,11 @@ +from .julia import jl +from .tensor import Tensor + + +def read(filename: str) -> Tensor: + julia_obj = jl.fread(filename) + return Tensor(julia_obj) + + +def write(filename: str, tns: Tensor) -> None: + jl.fwrite(filename, tns._obj) diff --git a/src/finch/julia.py b/src/finch/julia.py index 12fddef..323f28d 100644 --- a/src/finch/julia.py +++ b/src/finch/julia.py @@ -30,3 +30,4 @@ jl.seval("using Finch") jl.seval("using Random") +jl.seval("using TensorMarket") diff --git a/tests/data/matrix_1.ttx b/tests/data/matrix_1.ttx new file mode 100644 index 0000000..9c4de1c --- /dev/null +++ b/tests/data/matrix_1.ttx @@ -0,0 +1,17 @@ +%%MatrixMarket matrix coordinate integer general +3 5 15 +1 1 0 +2 1 1 +3 1 0 +1 2 0 +2 2 0 +3 2 5 +1 3 3 +2 3 0 +3 3 0 +1 4 2 +2 4 1 +3 4 0 +1 5 0 +2 5 0 +3 5 0 diff --git a/tests/test_io.py b/tests/test_io.py new file mode 100644 index 0000000..ec17186 --- /dev/null +++ b/tests/test_io.py @@ -0,0 +1,25 @@ +import os + +from numpy.testing import assert_equal + +import finch + +base_path = "tests/data" + + +def test_read(arr2d): + tns = finch.read(f"{base_path}/matrix_1.ttx") + + assert_equal(tns.todense(), arr2d) + + +def test_write(arr2d): + tns = finch.asarray(arr2d) + finch.write(f"{base_path}/tmp.ttx", tns) + + expected = open(f"{base_path}/matrix_1.ttx").read() + actual = open(f"{base_path}/tmp.ttx").read() + + assert actual == expected + + os.remove(f"{base_path}/tmp.ttx") From 8724f7de3cb1813c4fd3343cd3c875babe04f513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Thu, 13 Jun 2024 16:16:07 +0200 Subject: [PATCH 2/4] Apply review comments --- src/finch/io.py | 10 ++++++---- src/finch/julia.py | 24 +++++++++++++++++------- tests/test_io.py | 8 +++----- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/finch/io.py b/src/finch/io.py index f99e8b5..59ae6bf 100644 --- a/src/finch/io.py +++ b/src/finch/io.py @@ -1,11 +1,13 @@ +from pathlib import Path + from .julia import jl from .tensor import Tensor -def read(filename: str) -> Tensor: - julia_obj = jl.fread(filename) +def read(filename: Path | str) -> Tensor: + julia_obj = jl.fread(str(filename)) return Tensor(julia_obj) -def write(filename: str, tns: Tensor) -> None: - jl.fwrite(filename, tns._obj) +def write(filename: Path | str, tns: Tensor) -> None: + jl.fwrite(str(filename), tns._obj) diff --git a/src/finch/julia.py b/src/finch/julia.py index 323f28d..dca8450 100644 --- a/src/finch/julia.py +++ b/src/finch/julia.py @@ -8,20 +8,30 @@ _FINCH_REPO_PATH = os.environ.get("FINCH_REPO_PATH", default=None) _FINCH_REPO_URL = os.environ.get("FINCH_URL_PATH", default=None) +_TENSOR_MARKET_NAME = "TensorMarket" +_TENSOR_MARKET_HASH = "8b7d4fe7-0b45-4d0d-9dd8-5cc9b23b4b77" +_TENSOR_MARKET_VERSION = "0.2.0" + if _FINCH_REPO_PATH and _FINCH_REPO_URL: raise ValueError("FINCH_REPO_PATH and FINCH_URL_PATH can't be set at the same time.") +deps = juliapkg.deps.load_cur_deps() + if _FINCH_REPO_PATH: # Also account for empty string juliapkg.add(_FINCH_NAME, _FINCH_HASH, path=_FINCH_REPO_PATH, dev=True) elif _FINCH_REPO_URL: juliapkg.add(_FINCH_NAME, _FINCH_HASH, url=_FINCH_REPO_URL, dev=True) -else: - deps = juliapkg.deps.load_cur_deps() - if ( - deps.get("packages", {}).get(_FINCH_NAME, {}).get("version", None) - != _FINCH_VERSION - ): - juliapkg.add(_FINCH_NAME, _FINCH_HASH, version=_FINCH_VERSION) +elif ( + deps.get("packages", {}).get(_FINCH_NAME, {}).get("version", None) + != _FINCH_VERSION +): + juliapkg.add(_FINCH_NAME, _FINCH_HASH, version=_FINCH_VERSION) + +if ( + deps.get("packages", {}).get(_TENSOR_MARKET_NAME, {}).get("version", None) + != _FINCH_VERSION +): + juliapkg.add(_TENSOR_MARKET_NAME, _TENSOR_MARKET_HASH, version=_TENSOR_MARKET_VERSION) import juliacall as jc # noqa diff --git a/tests/test_io.py b/tests/test_io.py index ec17186..73581d1 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -13,13 +13,11 @@ def test_read(arr2d): assert_equal(tns.todense(), arr2d) -def test_write(arr2d): +def test_write(tmp_path, arr2d): tns = finch.asarray(arr2d) - finch.write(f"{base_path}/tmp.ttx", tns) + finch.write(tmp_path / "tmp.ttx", tns) expected = open(f"{base_path}/matrix_1.ttx").read() - actual = open(f"{base_path}/tmp.ttx").read() + actual = open(tmp_path / "tmp.ttx").read() assert actual == expected - - os.remove(f"{base_path}/tmp.ttx") From bbcb63cd8b77404e16185e8e3d4c3760f86b278d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Fri, 14 Jun 2024 10:09:28 +0200 Subject: [PATCH 3/4] Add remaining IO dependencies --- src/finch/io.py | 28 +++++++++++++++++++++++++--- src/finch/julia.py | 27 +++++++++------------------ 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/finch/io.py b/src/finch/io.py index 59ae6bf..ccf0df8 100644 --- a/src/finch/io.py +++ b/src/finch/io.py @@ -1,13 +1,35 @@ from pathlib import Path -from .julia import jl +from .julia import add_package, jl from .tensor import Tensor +def _import_deps(filename: str) -> None: + fn = filename + if fn.endswith(".mtx") or fn.endswith(".ttx") or fn.endswith(".tns"): + add_package("TensorMarket", hash="8b7d4fe7-0b45-4d0d-9dd8-5cc9b23b4b77", version="0.2.0") + jl.seval("using TensorMarket") + elif fn.endswith(".bspnpy"): + add_package("NPZ", hash="15e1cf62-19b3-5cfa-8e77-841668bca605", version="0.4.3") + jl.seval("using NPZ") + elif fn.endswith(".bsp.h5"): + add_package("HDF5", hash="f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f", version="0.17.2") + jl.seval("using HDF5") + else: + raise ValueError( + f"Unsupported file extension. Supported extensions are " + "`.mtx`, `.ttx`, `.tns`, `.bspnpy`, and `.bsp.h5`." + ) + + def read(filename: Path | str) -> Tensor: - julia_obj = jl.fread(str(filename)) + fn = str(filename) + _import_deps(fn) + julia_obj = jl.fread(fn) return Tensor(julia_obj) def write(filename: Path | str, tns: Tensor) -> None: - jl.fwrite(str(filename), tns._obj) + fn = str(filename) + _import_deps(fn) + jl.fwrite(fn, tns._obj) diff --git a/src/finch/julia.py b/src/finch/julia.py index dca8450..b7c0e8b 100644 --- a/src/finch/julia.py +++ b/src/finch/julia.py @@ -2,36 +2,28 @@ import juliapkg + +def add_package(name: str, hash: str, version: str) -> None: + deps = juliapkg.deps.load_cur_deps() + if (deps.get("packages", {}).get(name, {}).get("version", None) != version): + juliapkg.add(name, hash, version=version) + + _FINCH_NAME = "Finch" _FINCH_VERSION = "0.6.31" _FINCH_HASH = "9177782c-1635-4eb9-9bfb-d9dfa25e6bce" _FINCH_REPO_PATH = os.environ.get("FINCH_REPO_PATH", default=None) _FINCH_REPO_URL = os.environ.get("FINCH_URL_PATH", default=None) -_TENSOR_MARKET_NAME = "TensorMarket" -_TENSOR_MARKET_HASH = "8b7d4fe7-0b45-4d0d-9dd8-5cc9b23b4b77" -_TENSOR_MARKET_VERSION = "0.2.0" - if _FINCH_REPO_PATH and _FINCH_REPO_URL: raise ValueError("FINCH_REPO_PATH and FINCH_URL_PATH can't be set at the same time.") -deps = juliapkg.deps.load_cur_deps() - if _FINCH_REPO_PATH: # Also account for empty string juliapkg.add(_FINCH_NAME, _FINCH_HASH, path=_FINCH_REPO_PATH, dev=True) elif _FINCH_REPO_URL: juliapkg.add(_FINCH_NAME, _FINCH_HASH, url=_FINCH_REPO_URL, dev=True) -elif ( - deps.get("packages", {}).get(_FINCH_NAME, {}).get("version", None) - != _FINCH_VERSION -): - juliapkg.add(_FINCH_NAME, _FINCH_HASH, version=_FINCH_VERSION) - -if ( - deps.get("packages", {}).get(_TENSOR_MARKET_NAME, {}).get("version", None) - != _FINCH_VERSION -): - juliapkg.add(_TENSOR_MARKET_NAME, _TENSOR_MARKET_HASH, version=_TENSOR_MARKET_VERSION) +else: + add_package(_FINCH_NAME, _FINCH_HASH, _FINCH_VERSION) import juliacall as jc # noqa @@ -40,4 +32,3 @@ jl.seval("using Finch") jl.seval("using Random") -jl.seval("using TensorMarket") From 8813fd0e781925a6d256a44fcdfa182c2ca0d3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= Date: Fri, 14 Jun 2024 10:21:41 +0200 Subject: [PATCH 4/4] Add missing `resolve()` --- src/finch/julia.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/finch/julia.py b/src/finch/julia.py index b7c0e8b..a1e7dee 100644 --- a/src/finch/julia.py +++ b/src/finch/julia.py @@ -7,6 +7,7 @@ def add_package(name: str, hash: str, version: str) -> None: deps = juliapkg.deps.load_cur_deps() if (deps.get("packages", {}).get(name, {}).get("version", None) != version): juliapkg.add(name, hash, version=version) + juliapkg.resolve() _FINCH_NAME = "Finch"