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

tonegas / nnodely / 16502811447

24 Jul 2025 04:44PM UTC coverage: 97.767% (+0.1%) from 97.651%
16502811447

push

github

web-flow
New version 1.5.0

This pull request introduces version 1.5.0 of **nnodely**, featuring several updates:
1. Improved clarity of documentation and examples.
2. Support for managing multi-dataset features is now available.
3. DataFrames can now be used to create datasets.
4. Datasets can now be resampled.
5. Random data training has been fixed for both classic and recurrent training.
6. The `state` variable has been removed.
7. It is now possible to add or remove a connection or a closed loop.
8. Partial models can now be exported.
9. The `train` function and the result analysis have been separated.
10. A new function, `trainAndAnalyse`, is now available.
11. The report now works across all network types.
12. The training function code has been reorganized.

2901 of 2967 new or added lines in 53 files covered. (97.78%)

16 existing lines in 6 files now uncovered.

12652 of 12941 relevant lines covered (97.77%)

0.98 hits per line

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

90.14
/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✔
NEW
169
        obj = toStream(obj)
×
NEW
170
        check(type(obj) is Stream, TypeError,
×
171
              f"The type of {obj} is {type(obj)} and is not supported for sign operation.")
NEW
172
        super().__init__(sign_relation_name+str(Stream.count), obj.json, obj.dim)
×
NEW
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)
×
179
        check(type(obj) is Stream, TypeError,
×
180
              f"The type of {obj} is {type(obj)} and is not supported for sum operation.")
181
        super().__init__(sum_relation_name + str(Stream.count),obj.json,obj.dim)
×
182
        self.json['Relations'][self.name] = [sum_relation_name,[obj.name]]
×
183

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

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

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

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

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

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

221

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

335

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