• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tonegas / nnodely / 20077271476

09 Dec 2025 08:18PM UTC coverage: 98.1% (+0.3%) from 97.767%
20077271476

Pull #109

github

web-flow
Merge c710ae784 into 7b5c6388a
Pull Request #109: New version of nnodely

923 of 933 new or added lines in 38 files covered. (98.93%)

10 existing lines in 4 files now uncovered.

13266 of 13523 relevant lines covered (98.1%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.41
/nnodely/layers/arithmetic.py
1
import torch.nn as nn
1✔
2
import torch
1✔
3

4
from nnodely.basic.relation import ToStream, Stream, toStream
1✔
5
from nnodely.basic.model import Model
1✔
6
from nnodely.support.utils import check, enforce_types
1✔
7
from nnodely.layers.parameter import Parameter, Constant
1✔
8
from nnodely.support.jsonutils import merge, binary_cheks
1✔
9

10

11
# Binary operators
12
add_relation_name = 'Add'
1✔
13
sub_relation_name = 'Sub'
1✔
14
mul_relation_name = 'Mul'
1✔
15
div_relation_name = 'Div'
1✔
16
pow_relation_name = 'Pow'
1✔
17

18
# Unary operators
19
neg_relation_name = 'Neg'
1✔
20
sign_relation_name = 'Sign'
1✔
21

22
# Merge operator
23
sum_relation_name = 'Sum'
1✔
24

25
class Add(Stream, ToStream):
1✔
26
    """
27
        Implement the addition function between two tensors. 
28
        (it is also possible to use the classical math operator '+')
29

30
        See also:
31
            Official PyTorch Add documentation: 
32
            `torch.add <https://pytorch.org/docs/stable/generated/torch.add.html>`_
33

34
        :param input1: the first element of the addition
35
        :type obj: Tensor
36
        :param input2: the second element of the addition
37
        :type obj: Tensor
38

39
        Example:
40
            >>> add = Add(relation1, relation2)
41
            or
42
            >>> add = relation1 + relation2
43
    """
44
    @enforce_types
1✔
45
    def __init__(self, obj1:Stream|Parameter|Constant|int|float, obj2:Stream|Parameter|Constant|int|float) -> Stream:
1✔
46
        obj1, obj2, dim = binary_cheks(self, obj1, obj2, 'addition operators (+)')
1✔
47
        super().__init__(add_relation_name + str(Stream.count),merge(obj1.json,obj2.json),dim)
1✔
48
        self.json['Relations'][self.name] = [add_relation_name,[obj1.name,obj2.name]]
1✔
49

50
## TODO: check the scalar dimension, helpful for the offset
51
class Sub(Stream, ToStream):
1✔
52
    """
53
        Implement the subtraction function between two tensors. 
54
        (it is also possible to use the classical math operator '-')
55

56
        :param input1: the first element of the subtraction
57
        :type obj: Tensor
58
        :param input2: the second element of the subtraction
59
        :type obj: Tensor
60

61
        Example:
62
            >>> sub = Sub(relation1, relation2)
63
            or
64
            >>> sub = relation1 - relation2
65
    """
66
    @enforce_types
1✔
67
    def __init__(self, obj1:Stream|Parameter|Constant|int|float, obj2:Stream|Parameter|Constant|int|float) -> Stream:
1✔
68
        obj1, obj2, dim = binary_cheks(self, obj1, obj2, 'subtraction operators (-)')
1✔
69
        super().__init__(sub_relation_name + str(Stream.count),merge(obj1.json,obj2.json),dim)
1✔
70
        self.json['Relations'][self.name] = [sub_relation_name,[obj1.name,obj2.name]]
1✔
71

72
class Mul(Stream, ToStream):
1✔
73
    """
74
        Implement the multiplication function between two tensors. 
75
        (it is also possible to use the classical math operator '*')
76

77
        :param input1: the first element of the multiplication
78
        :type obj: Tensor
79
        :param input2: the second element of the multiplication
80
        :type obj: Tensor
81

82
        Example:
83
            >>> mul = Mul(relation1, relation2)
84
            or
85
            >>> mul = relation1 * relation2
86
    """
87
    @enforce_types
1✔
88
    def __init__(self, obj1:Stream|Parameter|Constant|int|float, obj2:Stream|Parameter|Constant|int|float) -> Stream:
1✔
89
        obj1, obj2, dim = binary_cheks(self, obj1, obj2, 'multiplication operators (*)')
1✔
90
        super().__init__(mul_relation_name + str(Stream.count),merge(obj1.json,obj2.json),dim)
1✔
91
        self.json['Relations'][self.name] = [mul_relation_name,[obj1.name,obj2.name]]
1✔
92

93
class Div(Stream, ToStream):
1✔
94
    """
95
        Implement the division function between two tensors. 
96
        (it is also possible to use the classical math operator '/')
97

98
        :param input1: the numerator of the division
99
        :type obj: Tensor
100
        :param input2: the denominator of the division
101
        :type obj: Tensor
102

103
        Example:
104
            >>> div = Div(relation1, relation2)
105
            or
106
            >>> div = relation1 / relation2
107
    """
108
    @enforce_types
1✔
109
    def __init__(self, obj1:Stream|Parameter|Constant|int|float, obj2:Stream|Parameter|Constant|int|float) -> Stream:
1✔
110
        obj1, obj2, dim = binary_cheks(self, obj1, obj2, 'division operators (/) ')
1✔
111
        super().__init__(div_relation_name + str(Stream.count),merge(obj1.json,obj2.json),dim)
1✔
112
        self.json['Relations'][self.name] = [div_relation_name,[obj1.name,obj2.name]]
1✔
113

114
class Pow(Stream, ToStream):
1✔
115
    """
116
        Implement the power function given an input and an exponent. 
117
        (it is also possible to use the classical math operator '**')
118

119
        See also:
120
            Official PyTorch pow documentation:
121
            `torch.pow <https://pytorch.org/docs/stable/generated/torch.pow.html>`_
122

123
        :param input: the base of the power function
124
        :type obj: Tensor
125
        :param exp: the exponent of the power function
126
        :type obj: float or Tensor
127

128
        Example:
129
            >>> pow = Pow(relation, exp)
130
            or
131
            >>> pow = relation1 ** relation2
132
    """
133
    @enforce_types
1✔
134
    def __init__(self, obj1:Stream|Parameter|Constant|int|float, obj2:Stream|Parameter|Constant|int|float) -> Stream:
1✔
135
        obj1, obj2, dim = binary_cheks(self, obj1, obj2, 'pow operators (**)')
1✔
136
        super().__init__(pow_relation_name + str(Stream.count),merge(obj1.json,obj2.json),dim)
1✔
137
        self.json['Relations'][self.name] = [pow_relation_name,[obj1.name,obj2.name]]
1✔
138

139
class Neg(Stream, ToStream):
1✔
140
    """
141
        Implement the negate function given an input. 
142

143
        :param input: the input to negate
144
        :type obj: Tensor
145

146
        Example:
147
            >>> x = Neg(x)
148
    """
149
    @enforce_types
1✔
150
    def __init__(self, obj:Stream|Parameter|Constant) -> Stream:
1✔
151
        obj = toStream(obj)
1✔
152
        check(type(obj) is Stream, TypeError,
1✔
153
              f"The type of {obj} is {type(obj)} and is not supported for neg operation.")
154
        super().__init__(neg_relation_name+str(Stream.count), obj.json, obj.dim)
1✔
155
        self.json['Relations'][self.name] = [neg_relation_name,[obj.name]]
1✔
156

157
class Sign(Stream, ToStream):
1✔
158
    """
159
        Implement the sign function given an input. 
160

161
        :param input: the input for the sign function
162
        :type obj: Tensor
163

164
        Example:
165
            >>> x = Sign(x)
166
    """
167
    @enforce_types
1✔
168
    def __init__(self, obj:Stream|Parameter|Constant) -> Stream:
1✔
169
        obj = toStream(obj)
×
170
        check(type(obj) is Stream, TypeError,
×
171
              f"The type of {obj} is {type(obj)} and is not supported for sign operation.")
172
        super().__init__(sign_relation_name+str(Stream.count), obj.json, obj.dim)
×
173
        self.json['Relations'][self.name] = [sign_relation_name,[obj.name]]
×
174

175
class Sum(Stream, ToStream):
1✔
176
    @enforce_types
1✔
177
    def __init__(self, obj:Stream|Parameter|Constant) -> Stream:
1✔
178
        obj = toStream(obj)
1✔
179
        check(type(obj) is Stream, TypeError,
1✔
180
              f"The type of {obj} is {type(obj)} and is not supported for sum operation.")
181
        obj.dim['dim'] = 1
1✔
182
        super().__init__(sum_relation_name + str(Stream.count),obj.json,obj.dim)
1✔
183
        self.json['Relations'][self.name] = [sum_relation_name,[obj.name]]
1✔
184

185
class Add_Layer(nn.Module):
1✔
186
    #: :noindex:
187
    def __init__(self):
1✔
188
        super(Add_Layer, self).__init__()
1✔
189

190
    def forward(self, *inputs):
1✔
191
        results = inputs[0]
1✔
192
        for input in inputs[1:]:
1✔
193
            results = results + input
1✔
194
        return results
1✔
195

196
def createAdd(name, *inputs):
1✔
197
    """
198
     :noindex:
199
    """
200
    return Add_Layer()
1✔
201

202
class Sub_Layer(nn.Module):
1✔
203
    """
204
     :noindex:
205
    """
206
    def __init__(self):
1✔
207
        super(Sub_Layer, self).__init__()
1✔
208

209
    def forward(self, *inputs):
1✔
210
        # Perform element-wise subtraction
211
        results = inputs[0]
1✔
212
        for input in inputs[1:]:
1✔
213
            results = results - input
1✔
214
        return results
1✔
215

216
def createSub(self, *inputs):
1✔
217
    """
218
     :noindex:
219
    """
220
    return Sub_Layer()
1✔
221

222

223
class Mul_Layer(nn.Module):
1✔
224
    """
225
     :noindex:
226
    """
227
    def __init__(self):
1✔
228
        super(Mul_Layer, self).__init__()
1✔
229

230
    def forward(self, *inputs):
1✔
231
        results = inputs[0]
1✔
232
        for input in inputs[1:]:
1✔
233
            results = results * input
1✔
234
        return results
1✔
235

236
def createMul(name, *inputs):
1✔
237
    """
238
     :noindex:
239
    """
240
    return Mul_Layer()
1✔
241

242
class Div_Layer(nn.Module):
1✔
243
    """
244
     :noindex:
245
    """
246
    def __init__(self):
1✔
247
        super(Div_Layer, self).__init__()
1✔
248

249
    def forward(self, *inputs):
1✔
250
        results = inputs[0]
1✔
251
        for input in inputs[1:]:
1✔
252
            results = results / input
1✔
253
        return results
1✔
254

255
def createDiv(name, *inputs):
1✔
256
    """
257
     :noindex:
258
    """
259
    return Div_Layer()
1✔
260

261
class Pow_Layer(nn.Module):
1✔
262
    """
263
     :noindex:
264
    """
265
    def __init__(self):
1✔
266
        super(Pow_Layer, self).__init__()
1✔
267

268
    def forward(self, *inputs):
1✔
269
        return torch.pow(inputs[0], inputs[1])
1✔
270

271
def createPow(name, *inputs):
1✔
272
    """
273
     :noindex:
274
    """
275
    return Pow_Layer()
1✔
276

277
class Neg_Layer(nn.Module):
1✔
278
    """
279
     :noindex:
280
    """
281
    def __init__(self):
1✔
282
        super(Neg_Layer, self).__init__()
1✔
283

284
    def forward(self, x):
1✔
285
        return -x
1✔
286

287
def createNeg(self, *inputs):
1✔
288
    """
289
     :noindex:
290
    """
291
    return Neg_Layer()
1✔
292

293
class Sign_Layer(nn.Module):
1✔
294
    """
295
     :noindex:
296
    """
297
    def __init__(self):
1✔
298
        super(Sign_Layer, self).__init__()
×
299

300
    def forward(self, x):
1✔
301
        return torch.sign(x)
×
302

303
def createSign(self, *inputs):
1✔
304
    """
305
     :noindex:
306
    """
307
    return Sign_Layer()
×
308

309
class Sum_Layer(nn.Module):
1✔
310
    """
311
     :noindex:
312
    """
313
    def __init__(self):
1✔
314
        super(Sum_Layer, self).__init__()
1✔
315

316
    def forward(self, inputs):
1✔
NEW
317
        return torch.sum(inputs, dim = 2, keepdim = True)
×
318

319
def createSum(name, *inputs):
1✔
320
    """
321
     :noindex:
322
    """
323
    return Sum_Layer()
1✔
324

325
setattr(Model, add_relation_name, createAdd)
1✔
326
setattr(Model, sub_relation_name, createSub)
1✔
327
setattr(Model, mul_relation_name, createMul)
1✔
328
setattr(Model, div_relation_name, createDiv)
1✔
329
setattr(Model, pow_relation_name, createPow)
1✔
330

331
setattr(Model, neg_relation_name, createNeg)
1✔
332
setattr(Model, sign_relation_name, createSign)
1✔
333

334
setattr(Model, sum_relation_name, createSum)
1✔
335

336

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc