11import math
22import torch
3- from torch import BoolTensor , LongTensor , Tensor
3+ from torch import BoolTensor , LongTensor , FloatTensor , Tensor
44import torch .nn .functional as F
55from collections import deque
66
@@ -482,12 +482,13 @@ def bind(input: Tensor, other: Tensor) -> Tensor:
482482
483483 Examples::
484484
485- >>> x = functional.random_hv(2, 3)
486- >>> x
487- tensor([[ 1., -1., -1.],
488- [ 1., 1., 1.]])
489- >>> functional.bind(x[0], x[1])
490- tensor([ 1., -1., -1.])
485+ >>> a, b = functional.random_hv(2, 10)
486+ >>> a
487+ tensor([-1., 1., -1., -1., 1., 1., -1., 1., 1., -1.])
488+ >>> b
489+ tensor([-1., -1., 1., 1., -1., -1., 1., 1., 1., 1.])
490+ >>> functional.bind(a, b)
491+ tensor([ 1., -1., -1., -1., -1., -1., -1., 1., 1., -1.])
491492
492493 """
493494 dtype = input .dtype
@@ -571,12 +572,13 @@ def bundle(input: Tensor, other: Tensor, *, tie: BoolTensor = None) -> Tensor:
571572
572573 Examples::
573574
574- >>> x = functional.random_hv(2, 3)
575- >>> x
576- tensor([[ 1., 1., 1.],
577- [-1., 1., -1.]])
578- >>> functional.bundle(x[0], x[1])
579- tensor([0., 2., 0.])
575+ >>> a, b = functional.random_hv(2, 10)
576+ >>> a
577+ tensor([ 1., -1., 1., -1., -1., 1., -1., -1., 1., -1.])
578+ >>> b
579+ tensor([ 1., -1., -1., 1., 1., 1., -1., 1., -1., 1.])
580+ >>> functional.bundle(a, b)
581+ tensor([ 2., -2., 0., 0., 0., 2., -2., 0., 0., 0.])
580582
581583 """
582584 dtype = input .dtype
@@ -891,6 +893,91 @@ def multiset(input: Tensor) -> Tensor:
891893
892894 return torch .sum (input , dim = dim , dtype = dtype )
893895
896+ def randsel (
897+ input : Tensor , other : Tensor , * , p : float = 0.5 , generator : torch .Generator = None
898+ ) -> Tensor :
899+ r"""Bundles two hypervectors by selecting random elements.
900+
901+ A bundling operation is used to aggregate information into a single hypervector.
902+ The resulting hypervector has elements selected at random from input or other.
903+
904+ .. math::
905+
906+ \oplus: \mathcal{H} \times \mathcal{H} \to \mathcal{H}
907+
908+ Aliased as ``torchhd.randsel``.
909+
910+ Args:
911+ input (Tensor): input hypervector
912+ other (Tensor): other input hypervector
913+ p (float, optional): probability of selecting elements from the input hypervector. Default: 0.5.
914+ generator (``torch.Generator``, optional): a pseudorandom number generator for sampling.
915+
916+ Shapes:
917+ - Input: :math:`(*)`
918+ - Other: :math:`(*)`
919+ - Output: :math:`(*)`
920+
921+ Examples::
922+
923+ >>> a, b = functional.random_hv(2, 10)
924+ >>> a
925+ tensor([ 1., -1., 1., -1., 1., -1., -1., -1., -1., 1.])
926+ >>> b
927+ tensor([ 1., -1., 1., -1., 1., 1., -1., 1., -1., 1.])
928+ >>> functional.randsel(a, b)
929+ tensor([ 1., -1., 1., -1., 1., 1., -1., 1., -1., 1.])
930+
931+ """
932+ select = torch .empty_like (input , dtype = torch .bool )
933+ select .bernoulli_ (1 - p , generator = generator )
934+ return input .where (select , other )
935+
936+
937+ def multirandsel (
938+ input : Tensor , * , p : FloatTensor = None , generator : torch .Generator = None
939+ ) -> Tensor :
940+ r"""Bundling multiple hypervectors by sampling random elements.
941+
942+ Bundles all the input hypervectors together.
943+ The resulting hypervector has elements selected at random from the input tensor of hypervectors.
944+
945+ .. math::
946+
947+ \bigoplus_{i=0}^{n-1} V_i
948+
949+ Args:
950+ input (Tensor): input hypervector tensor
951+ p (FloatTensor, optional): probability of selecting elements from the input hypervector. Default: uniform.
952+ generator (``torch.Generator``, optional): a pseudorandom number generator for sampling.
953+
954+ Shapes:
955+ - Input: :math:`(*, n, d)`
956+ - Probability (p): :math:`(*, n)`
957+ - Output: :math:`(*, d)`
958+
959+ Examples::
960+
961+ >>> x = functional.random_hv(5, 10)
962+ >>> x
963+ tensor([[-1., 1., 1., 1., -1., 1., 1., -1., 1., -1.],
964+ [-1., 1., 1., 1., -1., 1., -1., -1., -1., -1.],
965+ [-1., -1., 1., -1., -1., 1., -1., 1., 1., -1.],
966+ [ 1., 1., -1., 1., -1., -1., 1., -1., 1., 1.],
967+ [ 1., -1., -1., 1., 1., 1., 1., -1., -1., -1.]])
968+ >>> functional.multirandsel(x)
969+ tensor([ 1., -1., -1., 1., -1., 1., 1., 1., 1., -1.])
970+
971+ """
972+ d = input .size (- 1 )
973+ device = input .device
974+
975+ if p is None :
976+ p = torch .ones (input .shape [:- 1 ], dtype = torch .float , device = device )
977+
978+ select = torch .multinomial (p , d , replacement = True , generator = generator )
979+ select .unsqueeze_ (- 2 )
980+ return input .gather (- 2 , select ).squeeze (- 2 )
894981
895982multibundle = multiset
896983
@@ -917,13 +1004,15 @@ def multibind(input: Tensor) -> Tensor:
9171004
9181005 Examples::
9191006
920- >>> x = functional.random_hv(3, 3 )
1007+ >>> x = functional.random_hv(5, 10 )
9211008 >>> x
922- tensor([[ 1., 1., 1.],
923- [-1., 1., 1.],
924- [-1., 1., -1.]])
1009+ tensor([[ 1., -1., -1., -1., -1., 1., 1., 1., -1., 1.],
1010+ [ 1., 1., -1., -1., 1., 1., -1., -1., 1., -1.],
1011+ [-1., -1., 1., -1., -1., -1., -1., 1., -1., -1.],
1012+ [-1., 1., -1., 1., 1., -1., -1., -1., 1., 1.],
1013+ [-1., -1., 1., -1., 1., -1., 1., 1., -1., 1.]])
9251014 >>> functional.multibind(x)
926- tensor([ 1., 1., - 1.])
1015+ tensor([-1., - 1., -1., 1., 1., -1., -1., 1., -1., 1.])
9271016
9281017 """
9291018 dtype = input .dtype
0 commit comments