Skip to content

Commit fe6c4bc

Browse files
Add sparsity parameter to level and circular hypervectors (#56)
* Add sparsity parameter to level and circular-hv sets * Add sparsity parameter to level and circular-hv sets * Add to documentation * Add tests Co-authored-by: mikeheddes <mikeheddes@gmail.com>
1 parent dc3c8cb commit fe6c4bc

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

torchhd/functional.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ def level_hv(
146146
num_embeddings: int,
147147
embedding_dim: int,
148148
*,
149+
sparsity=0.5,
149150
randomness=0.0,
150151
generator=None,
151152
dtype=None,
@@ -162,6 +163,7 @@ def level_hv(
162163
Args:
163164
num_embeddings (int): the number of hypervectors to generate.
164165
embedding_dim (int): the dimensionality of the hypervectors.
166+
sparsity (float, optional): the expected fraction of elements to be +1. Default: ``0.5``.
165167
randomness (float, optional): r-value to interpolate between level at ``0.0`` and random-hypervectors at ``1.0``. Default: ``0.0``.
166168
generator (``torch.Generator``, optional): a pseudorandom number generator for sampling.
167169
dtype (``torch.dtype``, optional): the desired data type of returned tensor. Default: if ``None``, uses a global default (see ``torch.set_default_tensor_type()``).
@@ -204,6 +206,7 @@ def level_hv(
204206
int(math.ceil(span + 1)),
205207
embedding_dim,
206208
generator=generator,
209+
sparsity=sparsity,
207210
dtype=dtype,
208211
device=device,
209212
)
@@ -244,6 +247,7 @@ def circular_hv(
244247
num_embeddings: int,
245248
embedding_dim: int,
246249
*,
250+
sparsity=0.5,
247251
randomness=0.0,
248252
generator=None,
249253
dtype=None,
@@ -260,6 +264,7 @@ def circular_hv(
260264
Args:
261265
num_embeddings (int): the number of hypervectors to generate.
262266
embedding_dim (int): the dimensionality of the hypervectors.
267+
sparsity (float, optional): the expected fraction of elements to be +1. Default: ``0.5``.
263268
randomness (float, optional): r-value to interpolate between circular at ``0.0`` and random-hypervectors at ``1.0``. Default: ``0.0``.
264269
generator (``torch.Generator``, optional): a pseudorandom number generator for sampling.
265270
dtype (``torch.dtype``, optional): the desired data type of returned tensor. Default: if ``None``, uses a global default (see ``torch.set_default_tensor_type()``).
@@ -307,6 +312,7 @@ def circular_hv(
307312
int(math.ceil(span + 1)),
308313
embedding_dim,
309314
generator=generator,
315+
sparsity=sparsity,
310316
dtype=dtype,
311317
device=device,
312318
)

torchhd/tests/test_basis_hv.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,14 @@ def test_sparsity(self):
117117
generator = torch.Generator()
118118
generator.manual_seed(2147483644)
119119

120-
hv = functional.random_hv(100, 10000, generator=generator, sparsity=1)
120+
hv = functional.random_hv(1000, 10000, generator=generator, sparsity=1)
121121
assert torch.all(hv == 1).item()
122122

123-
hv = functional.random_hv(100, 10000, generator=generator, sparsity=0)
123+
hv = functional.random_hv(1000, 10000, generator=generator, sparsity=0)
124124
assert torch.all(hv == -1).item()
125125

126-
hv = functional.random_hv(100, 10000, generator=generator, sparsity=0.5)
127-
assert between(torch.sum(hv == -1).div(10000 * 100).item(), 0.499, 0.501)
126+
hv = functional.random_hv(1000, 10000, generator=generator, sparsity=0.5)
127+
assert between(torch.sum(hv == -1).div(10000 * 1000).item(), 0.499, 0.501)
128128

129129
def test_orthogonality(self):
130130
generator = torch.Generator()
@@ -257,6 +257,23 @@ def test_value(self):
257257
(0.249 < sims_diff) & (sims_diff < 0.251)
258258
).item(), "similarity decreases linearly"
259259

260+
def test_sparsity(self):
261+
generator = torch.Generator()
262+
generator.manual_seed(2147287646)
263+
264+
hv = functional.level_hv(1000, 10000, generator=generator, sparsity=1)
265+
assert torch.all(hv == 1).item()
266+
267+
hv = functional.level_hv(1000, 10000, generator=generator, sparsity=0)
268+
assert torch.all(hv == -1).item()
269+
270+
sparsity = [None] * 100
271+
for i in range(100):
272+
hv = functional.level_hv(100, 10000, generator=generator, sparsity=0.5)
273+
sparsity[i] = torch.sum(hv == -1).div(10000 * 100)
274+
assert between(torch.vstack(sparsity).mean().item(), 0.499, 0.501)
275+
276+
260277
def test_device(self):
261278
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
262279
hv = functional.level_hv(3, 52, device=device)
@@ -368,6 +385,22 @@ def test_value(self):
368385
(0.249 < abs_sims_diff) & (abs_sims_diff < 0.251)
369386
).item(), "similarity decreases linearly"
370387

388+
def test_sparsity(self):
389+
generator = torch.Generator()
390+
generator.manual_seed(2147487649)
391+
392+
hv = functional.circular_hv(100, 10000, generator=generator, sparsity=1)
393+
assert torch.all(hv == 1).item()
394+
395+
hv = functional.circular_hv(100, 10000, generator=generator, sparsity=0)
396+
assert torch.all(hv == -1).item()
397+
398+
sparsity = [None] * 100
399+
for i in range(100):
400+
hv = functional.circular_hv(100, 10000, generator=generator, sparsity=0.5)
401+
sparsity[i] = torch.sum(hv == -1).div(10000 * 100)
402+
assert between(torch.vstack(sparsity).mean().item(), 0.499, 0.501)
403+
371404
def test_device(self):
372405
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
373406
hv = functional.circular_hv(3, 52, device=device)

0 commit comments

Comments
 (0)