Skip to content

Commit cf9598a

Browse files
committed
Adding export_data. Adding tests for export_data. Cleaning up test data.
1 parent 1cc199f commit cf9598a

File tree

6 files changed

+222
-78
lines changed

6 files changed

+222
-78
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ build/
1010
.ipynb_checkpoints
1111
htmlcov
1212
__pycache__
13-
.vs*
13+
.vs*
14+
TestResults

TensorToolbox/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from TensorToolbox.cp_als import cp_als
2020

2121
from TensorToolbox.import_data import import_data
22+
from TensorToolbox.export_data import export_data
2223

2324
import warnings
2425
def ignore_warnings(ignore=True):

TensorToolbox/export_data.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Copyright 2022 National Technology & Engineering Solutions of Sandia,
2+
# LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the
3+
# U.S. Government retains certain rights in this software.
4+
5+
import numpy as np
6+
import os
7+
import TensorToolbox as ttb
8+
9+
def export_data(data, filename, fmt_data=None, fmt_weights=None):
10+
"""
11+
Export tensor-related data to a file.
12+
"""
13+
# open file
14+
fp = open(filename, 'w')
15+
16+
if isinstance(data, ttb.tensor):
17+
print('tensor', file=fp)
18+
export_size(fp, data.shape)
19+
export_array(fp, data.data, fmt_data)
20+
21+
elif isinstance(data, ttb.sptensor):
22+
print('sptensor', file=fp)
23+
export_sparse_size(fp, data)
24+
export_sparse_array(fp, data, fmt_data)
25+
26+
elif isinstance(data, ttb.ktensor):
27+
print('ktensor', file=fp)
28+
export_size(fp, data.shape)
29+
export_rank(fp, data)
30+
export_weights(fp, data, fmt_weights)
31+
for n in range(data.ndims):
32+
print('matrix', file=fp)
33+
export_size(fp, data.factor_matrices[n].shape)
34+
export_factor(fp, data.factor_matrices[n], fmt_data)
35+
"""
36+
fprintf(fid, 'ktensor\n');
37+
export_size(fid, size(A));
38+
export_rank(fid, A);
39+
export_lambda(fid, A.lambda, fmt_lambda);
40+
for n = 1:length(size(A))
41+
fprintf(fid, 'matrix\n');
42+
export_size(fid, size(A.U{n}));
43+
export_factor(fid, A.U{n}, fmt_data);
44+
end
45+
"""
46+
47+
elif isinstance(data, np.ndarray):
48+
print('matrix', file=fp)
49+
export_size(fp, data.shape)
50+
export_array(fp, data, fmt_data)
51+
52+
else:
53+
assert False, 'Invalid data type for export'
54+
55+
def export_size(fp, shape):
56+
# Export the size of something to a file
57+
print(f'{len(shape)}', file=fp) # # of dimensions on one line
58+
shape_str = ' '.join([str(d) for d in shape])
59+
print(f'{shape_str}', file=fp) # size of each dimensions on the next line
60+
61+
def export_rank(fp, data):
62+
# Export the rank of a ktensor to a file
63+
print(f'{len(data.weights)}', file=fp) # ktensor rank on one line
64+
65+
def export_weights(fp, data, fmt_weights):
66+
# Export dense data that supports numel and linear indexing
67+
if not fmt_weights: fmt_weights = '%.16e'
68+
data.weights.tofile(fp, sep=' ', format=fmt_weights)
69+
print(file=fp)
70+
71+
def export_array(fp, data, fmt_data):
72+
# Export dense data that supports numel and linear indexing
73+
if not fmt_data: fmt_data = '%.16e'
74+
data.tofile(fp, sep='\n', format=fmt_data)
75+
print(file=fp)
76+
77+
def export_factor(fp, data, fmt_data):
78+
# Export dense data that supports numel and linear indexing
79+
if not fmt_data: fmt_data = '%.16e'
80+
for i in range(data.shape[0]):
81+
row = data[i,:]
82+
row.tofile(fp, sep=' ', format=fmt_data)
83+
print(file=fp)
84+
85+
def export_sparse_size(fp, A):
86+
# Export the size of something to a file
87+
print(f'{len(A.shape)}', file=fp) # # of dimensions on one line
88+
shape_str = ' '.join([str(d) for d in A.shape])
89+
print(f'{shape_str}', file=fp) # size of each dimensions on the next line
90+
print(f'{A.nnz}', file=fp) # number of nonzeros
91+
92+
def export_sparse_array(fp, A, fmt_data):
93+
# Export sparse array data in coordinate format
94+
if not fmt_data: fmt_data = '%.16e'
95+
# TODO: looping through all values may take a long time, can this be more efficient?
96+
for i in range(A.nnz):
97+
# 0-based indexing in package, 1-based indexing in file
98+
subs = A.subs[i,:] + 1
99+
subs.tofile(fp, sep=' ', format="%d")
100+
print(end=' ', file=fp)
101+
val = A.vals[i][0]
102+
val.tofile(fp, sep=' ', format=fmt_data)
103+
print(file=fp)

tests/data/matrix.tns

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
matrix
22
2
33
4 2
4-
1.0000000000000000e+00 5.0000000000000000e+00
5-
2.0000000000000000e+00 6.0000000000000000e+00
6-
3.0000000000000000e+00 7.0000000000000000e+00
7-
4.0000000000000000e+00 8.0000000000000000e+00
4+
1.0000000000000000e+00
5+
5.0000000000000000e+00
6+
2.0000000000000000e+00
7+
6.0000000000000000e+00
8+
3.0000000000000000e+00
9+
7.0000000000000000e+00
10+
4.0000000000000000e+00
11+
8.0000000000000000e+00

tests/data/sptensor_zero_based_index.tns

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

tests/test_import_export_data.py

Lines changed: 108 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,54 @@
88
import TensorToolbox as ttb
99

1010
@pytest.fixture()
11-
def sample_tensor_2way():
12-
data = np.array([[1., 2., 3.], [4., 5., 6.]])
13-
shape = (2, 3)
14-
params = {'data':data, 'shape': shape}
15-
tensorInstance = ttb.tensor().from_data(data, shape)
16-
return params, tensorInstance
11+
def sample_tensor():
12+
# truth data
13+
T = ttb.tensor.from_data(np.ones((3,3,3)), (3,3,3))
14+
return T
1715

1816
@pytest.fixture()
19-
def sample_tensor_3way():
20-
data = np.array([1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.])
21-
shape = (2, 3, 2)
22-
params = {'data':np.reshape(data, np.array(shape), order='F'), 'shape': shape}
23-
tensorInstance = ttb.tensor().from_data(data, shape)
24-
return params, tensorInstance
17+
def sample_sptensor():
18+
# truth data
19+
subs = np.array([[0, 0, 0],[0, 2, 2],[1, 1, 1],[1, 2, 0],[1, 2, 1],[1, 2, 2],
20+
[1, 3, 1],[2, 0, 0],[2, 0, 1],[2, 2, 0],[2, 2, 1],[2, 3, 0],
21+
[2, 3, 2],[3, 0, 0],[3, 0, 1],[3, 2, 0],[4, 0, 2],[4, 3, 2]])
22+
vals = np.reshape(np.array(range(1,19)),(18,1))
23+
shape = (5, 4, 3)
24+
S = ttb.sptensor().from_data(subs, vals, shape)
25+
return S
2526

2627
@pytest.fixture()
27-
def sample_tensor_4way():
28-
data = np.arange(1, 82)
29-
shape = (3, 3, 3, 3)
30-
params = {'data':np.reshape(data, np.array(shape), order='F'), 'shape': shape}
31-
tensorInstance = ttb.tensor().from_data(data, shape)
32-
return params, tensorInstance
28+
def sample_ktensor():
29+
# truth data
30+
weights = np.array([3, 2])
31+
fm0 = np.array([[1., 5.], [2., 6.], [3., 7.], [4., 8.]])
32+
fm1 = np.array([[ 2., 7.], [ 3., 8.], [ 4., 9.], [ 5., 10.], [ 6., 11.]])
33+
fm2 = np.array([[3., 6.], [4., 7.], [5., 8.]])
34+
factor_matrices = [fm0, fm1, fm2]
35+
K = ttb.ktensor.from_data(weights, factor_matrices)
36+
return K
37+
38+
@pytest.fixture()
39+
def sample_array():
40+
# truth data
41+
M = np.array([[1., 5.], [2., 6.], [3., 7.], [4., 8.]])
42+
return M
3343

3444
@pytest.mark.indevelopment
35-
def test_import_data_tensor():
45+
def test_import_data_tensor(sample_tensor):
3646
# truth data
37-
T = ttb.tensor.from_data(np.ones((3,3,3)), (3,3,3))
47+
T = sample_tensor
3848

3949
# imported data
4050
data_filename = os.path.join(os.path.dirname(__file__),'data','tensor.tns')
4151
X = ttb.import_data(data_filename)
4252

43-
assert X.shape == (3, 3, 3)
4453
assert T.isequal(X)
4554

4655
@pytest.mark.indevelopment
47-
def test_import_data_sptensor():
56+
def test_import_data_sptensor(sample_sptensor):
4857
# truth data
49-
subs = np.array([[0, 0, 0],[0, 2, 2],[1, 1, 1],[1, 2, 0],[1, 2, 1],[1, 2, 2],
50-
[1, 3, 1],[2, 0, 0],[2, 0, 1],[2, 2, 0],[2, 2, 1],[2, 3, 0],
51-
[2, 3, 2],[3, 0, 0],[3, 0, 1],[3, 2, 0],[4, 0, 2],[4, 3, 2]])
52-
vals = np.reshape(np.array(range(1,19)),(18,1))
53-
shape = (5, 4, 3)
54-
S = ttb.sptensor().from_data(subs, vals, shape)
58+
S = sample_sptensor
5559

5660
# imported data
5761
data_filename = os.path.join(os.path.dirname(__file__),'data','sptensor.tns')
@@ -60,49 +64,102 @@ def test_import_data_sptensor():
6064
assert S.isequal(X)
6165

6266
@pytest.mark.indevelopment
63-
def test_import_data_ktensor():
67+
def test_import_data_ktensor(sample_ktensor):
6468
# truth data
65-
weights = np.array([3, 2])
66-
fm0 = np.array([[1., 5.], [2., 6.], [3., 7.], [4., 8.]])
67-
fm1 = np.array([[ 2., 7.], [ 3., 8.], [ 4., 9.], [ 5., 10.], [ 6., 11.]])
68-
fm2 = np.array([[3., 6.], [4., 7.], [5., 8.]])
69-
factor_matrices = [fm0, fm1, fm2]
70-
K = ttb.ktensor.from_data(weights, factor_matrices)
71-
69+
K = sample_ktensor
70+
7271
# imported data
7372
data_filename = os.path.join(os.path.dirname(__file__),'data','ktensor.tns')
7473
X = ttb.import_data(data_filename)
7574

7675
assert K.isequal(X)
7776

7877
@pytest.mark.indevelopment
79-
def test_import_data_array():
78+
def test_import_data_array(sample_array):
8079
# truth data
81-
M = np.array([[1., 5.], [2., 6.], [3., 7.], [4., 8.]])
82-
print('\nM')
83-
print(M)
84-
80+
M = sample_array
81+
8582
# imported data
8683
data_filename = os.path.join(os.path.dirname(__file__),'data','matrix.tns')
8784
X = ttb.import_data(data_filename)
88-
print('\nX')
89-
print(X)
9085

9186
assert (M == X).all()
9287

9388
@pytest.mark.indevelopment
94-
def test_export_data_tensor():
95-
pass
89+
def test_export_data_tensor(sample_tensor):
90+
# truth data
91+
T = sample_tensor
92+
93+
data_filename = os.path.join(os.path.dirname(__file__),'data','tensor.out')
94+
ttb.export_data(T, data_filename)
95+
96+
X = ttb.import_data(data_filename)
97+
assert T.isequal(X)
98+
os.unlink(data_filename)
99+
100+
data_filename = os.path.join(os.path.dirname(__file__),'data','tensor_int.out')
101+
ttb.export_data(T, data_filename, fmt_data='%d')
102+
103+
X = ttb.import_data(data_filename)
104+
assert T.isequal(X)
105+
os.unlink(data_filename)
96106

97107
@pytest.mark.indevelopment
98-
def test_export_data_sptensor():
99-
pass
108+
def test_export_data_sptensor(sample_sptensor):
109+
# truth data
110+
S = sample_sptensor
111+
112+
# imported data
113+
data_filename = os.path.join(os.path.dirname(__file__),'data','sptensor.out')
114+
ttb.export_data(S, data_filename)
115+
116+
X = ttb.import_data(data_filename)
117+
assert S.isequal(X)
118+
os.unlink(data_filename)
119+
120+
data_filename = os.path.join(os.path.dirname(__file__),'data','sptensor_int.out')
121+
ttb.export_data(S, data_filename, fmt_data='%d')
122+
123+
X = ttb.import_data(data_filename)
124+
assert S.isequal(X)
125+
os.unlink(data_filename)
100126

101127
@pytest.mark.indevelopment
102-
def test_export_data_ktensor():
103-
pass
128+
def test_export_data_ktensor(sample_ktensor):
129+
# truth data
130+
K = sample_ktensor
131+
132+
# imported data
133+
data_filename = os.path.join(os.path.dirname(__file__),'data','ktensor.out')
134+
ttb.export_data(K, data_filename)
135+
136+
X = ttb.import_data(data_filename)
137+
assert K.isequal(X)
138+
os.unlink(data_filename)
139+
140+
data_filename = os.path.join(os.path.dirname(__file__),'data','ktensor_int.out')
141+
ttb.export_data(K, data_filename, fmt_data='%d', fmt_weights='%d')
142+
143+
X = ttb.import_data(data_filename)
144+
assert K.isequal(X)
145+
os.unlink(data_filename)
104146

105147
@pytest.mark.indevelopment
106-
def test_export_data_array():
107-
pass
148+
def test_export_data_array(sample_array):
149+
# truth data
150+
M = sample_array
151+
152+
# imported data
153+
data_filename = os.path.join(os.path.dirname(__file__),'data','matrix.out')
154+
ttb.export_data(M, data_filename)
108155

156+
X = ttb.import_data(data_filename)
157+
assert (M == X).all()
158+
os.unlink(data_filename)
159+
160+
data_filename = os.path.join(os.path.dirname(__file__),'data','matrix_int.out')
161+
ttb.export_data(M, data_filename, fmt_data='%d')
162+
163+
X = ttb.import_data(data_filename)
164+
assert (M == X).all()
165+
os.unlink(data_filename)

0 commit comments

Comments
 (0)