GCC Code Coverage Report


Directory: src/athena/
File: src/athena/athena_dynamic_lno_layer.f90
Date: 2026-04-15 16:08:59
Exec Total Coverage
Lines: 375 431 87.0%
Functions: 0 0 -%
Branches: 1070 2220 48.2%

Line Branch Exec Source
1 module athena__dynamic_lno_layer
2 !! Module containing implementation of a Laplace Neural Operator layer
3 !!
4 !! This module implements a Laplace Neural Operator (LNO) layer that
5 !! approximates an integral kernel operator in the Laplace-transform domain.
6 !! It combines a spectral pathway (encode → spectral mixing → decode)
7 !! with a local affine bypass:
8 !!
9 !! \[ \mathbf{v} = \sigma\!\bigl(
10 !! \underbrace{\mathbf{D}\,\mathbf{R}\,\mathbf{E}\,\mathbf{u}}_{\text{spectral}}
11 !! + \underbrace{\mathbf{W}\,\mathbf{u}}_{\text{local}}
12 !! + \mathbf{b}\bigr) \]
13 !!
14 !! where:
15 !! - \(\mathbf{u} \in \mathbb{R}^{n_{in}}\) is the discretised input
16 !! - \(\boldsymbol{\mu} \in \mathbb{R}^{M}\) are learnable Laplace-domain
17 !! poles that define dynamic bases via \(H(s)=\sum_n \beta_n/(s-\mu_n)\)
18 !! - \(\mathbf{E}(\boldsymbol{\mu}) \in \mathbb{R}^{M \times n_{in}}\) is
19 !! the pole-residue encoder: \(E_{k,j}=\exp(-\mu_k\,t_j)\),
20 !! \(t_j = (j{-}1)/(n_{in}{-}1)\)
21 !! - \(\boldsymbol{\beta} \in \mathbb{R}^{M}\) are learnable residues;
22 !! \(\mathrm{diag}(\boldsymbol{\beta})\) replaces the former full mixing R
23 !! - \(\mathbf{D}(\boldsymbol{\mu}) \in \mathbb{R}^{n_{out} \times M}\) is
24 !! the pole-residue decoder: \(D_{i,k}=\exp(-\mu_k\,\tau_i)\),
25 !! \(\tau_i = (i{-}1)/(n_{out}{-}1)\)
26 !! - \(\mathbf{W} \in \mathbb{R}^{n_{out} \times n_{in}}\) are the
27 !! local (bypass) weights
28 !! - \(\mathbf{b} \in \mathbb{R}^{n_{out}}\) is the bias
29 !! - \(\sigma\) is the activation function
30 !! - \(M\) = num_modes, the number of spectral poles
31 !!
32 !! Bases \(\mathbf{E}\) and \(\mathbf{D}\) are rebuilt from the current poles
33 !! at every forward call via \texttt{rebuild\_bases}.
34 !!
35 !! Number of parameters (learnable):
36 !! \(2M + n_{out}\,n_{in}\) without bias,
37 !! \(2M + n_{out}\,n_{in} + n_{out}\) with bias.
38 use coreutils, only: real32, stop_program, pi
39 use athena__base_layer, only: learnable_layer_type, base_layer_type
40 use athena__misc_types, only: base_actv_type, base_init_type, &
41 onnx_attribute_type, &
42 onnx_node_type, onnx_initialiser_type, onnx_tensor_type
43 use athena__onnx_nop_utils, only: emit_nop_input_transpose, &
44 emit_nop_output_tail, emit_float_initialiser, emit_matrix_initialiser
45 use diffstruc, only: array_type, matmul, operator(+), operator(*)
46 use athena__diffstruc_extd, only: lno_encode, lno_decode, elem_scale
47 implicit none
48
49
50 private
51
52 public :: dynamic_lno_layer_type
53 public :: read_dynamic_lno_layer
54
55
56 type, extends(learnable_layer_type) :: dynamic_lno_layer_type
57 !! Type for a pole-residue Laplace Neural Operator layer
58 integer :: num_inputs
59 !! Number of inputs (discretisation points)
60 integer :: num_outputs
61 !! Number of outputs (discretisation points)
62 integer :: num_modes
63 !! Number of Laplace spectral modes
64 type(array_type), dimension(1) :: z
65 !! Temporary array for pre-activation values
66 contains
67 procedure, pass(this) :: get_num_params => get_num_params_dynamic_lno
68 procedure, pass(this) :: set_hyperparams => set_hyperparams_dynamic_lno
69 procedure, pass(this) :: init => init_dynamic_lno
70 procedure, pass(this) :: print_to_unit => print_to_unit_dynamic_lno
71 procedure, pass(this) :: read => read_dynamic_lno
72 procedure, pass(this) :: get_bases => get_bases_dynamic_lno
73
74 procedure, pass(this) :: forward => forward_dynamic_lno
75 procedure, pass(this) :: get_attributes => get_attributes_dynamic_lno
76 procedure, pass(this) :: emit_onnx_nodes => emit_onnx_nodes_dynamic_lno
77
78 final :: finalise_dynamic_lno
79 end type dynamic_lno_layer_type
80
81 interface dynamic_lno_layer_type
82 module function layer_setup( &
83 num_outputs, num_modes, num_inputs, use_bias, &
84 activation, &
85 kernel_initialiser, bias_initialiser, verbose &
86 ) result(layer)
87 integer, intent(in) :: num_outputs
88 integer, intent(in) :: num_modes
89 integer, optional, intent(in) :: num_inputs
90 logical, optional, intent(in) :: use_bias
91 class(*), optional, intent(in) :: activation
92 class(*), optional, intent(in) :: kernel_initialiser, bias_initialiser
93 integer, optional, intent(in) :: verbose
94 type(dynamic_lno_layer_type) :: layer
95 end function layer_setup
96 end interface dynamic_lno_layer_type
97
98
99
100 contains
101
102 !###############################################################################
103 26 subroutine finalise_dynamic_lno(this)
104 !! Finalise the dynamic Laplace neural operator layer
105 implicit none
106
107 ! Arguments
108 type(dynamic_lno_layer_type), intent(inout) :: this
109 !! Layer instance to release
110
111
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
26 if(allocated(this%input_shape)) deallocate(this%input_shape)
112
4/6
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
26 if(allocated(this%output)) deallocate(this%output)
113
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 23 times.
26 if(this%z(1)%allocated) call this%z(1)%deallocate()
114
115 26 end subroutine finalise_dynamic_lno
116 !###############################################################################
117
118
119 !###############################################################################
120 12 pure function get_num_params_dynamic_lno(this) result(num_params)
121 !! Return the number of learnable parameters for the layer
122 implicit none
123
124 ! Arguments
125 class(dynamic_lno_layer_type), intent(in) :: this
126 !! Layer instance
127 integer :: num_params
128 !! Total number of learnable parameters
129
130 ! mu: num_modes, beta: num_modes, W: n_out * n_in, b: n_out (optional)
131 num_params = 2 * this%num_modes + &
132 12 this%num_outputs * this%num_inputs
133
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if(this%use_bias) num_params = num_params + this%num_outputs
134
135 12 end function get_num_params_dynamic_lno
136 !###############################################################################
137
138
139 !###############################################################################
140 12 module function layer_setup( &
141 num_outputs, num_modes, num_inputs, &
142 use_bias, &
143 activation, &
144 kernel_initialiser, bias_initialiser, verbose &
145
9/16
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
24 ) result(layer)
146 use athena__activation, only: activation_setup
147 use athena__initialiser, only: initialiser_setup
148 implicit none
149
150 ! Arguments
151 integer, intent(in) :: num_outputs
152 !! Number of output features
153 integer, intent(in) :: num_modes
154 !! Number of learnable spectral poles
155 integer, optional, intent(in) :: num_inputs
156 !! Number of input features when known at construction time
157 logical, optional, intent(in) :: use_bias
158 !! Whether to allocate a bias term
159 class(*), optional, intent(in) :: activation
160 !! Activation function specification
161 class(*), optional, intent(in) :: kernel_initialiser, bias_initialiser
162 !! Kernel and bias initialiser specifications
163 integer, optional, intent(in) :: verbose
164 !! Verbosity level
165
166 type(dynamic_lno_layer_type) :: layer
167 !! Constructed dynamic LNO layer
168
169 ! Local variables
170 integer :: verbose_ = 0
171 !! Effective verbosity level
172 logical :: use_bias_ = .true.
173 !! Effective bias flag
174 36 class(base_actv_type), allocatable :: activation_
175 !! Materialised activation object
176 12 class(base_init_type), allocatable :: kernel_initialiser_, bias_initialiser_
177 !! Materialised kernel and bias initialisers
178
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(present(verbose)) verbose_ = verbose
180
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if(present(use_bias)) use_bias_ = use_bias
181
182
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
12 if(present(activation))then
183
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 8 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 8 times.
✓ Branch 17 taken 8 times.
✗ Branch 18 not taken.
8 activation_ = activation_setup(activation)
184 else
185
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 4 times.
✓ Branch 17 taken 4 times.
✗ Branch 18 not taken.
4 activation_ = activation_setup("none")
186 end if
187
188
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12 if(present(kernel_initialiser))then
189 kernel_initialiser_ = initialiser_setup(kernel_initialiser)
190 end if
191
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12 if(present(bias_initialiser))then
192 bias_initialiser_ = initialiser_setup(bias_initialiser)
193 end if
194
195 call layer%set_hyperparams( &
196 num_outputs = num_outputs, &
197 num_modes = num_modes, &
198 use_bias = use_bias_, &
199 activation = activation_, &
200 kernel_initialiser = kernel_initialiser_, &
201 bias_initialiser = bias_initialiser_, &
202 verbose = verbose_ &
203 12 )
204
205
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 10 times.
22 if(present(num_inputs)) call layer%init(input_shape=[num_inputs])
206
207
13/28
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 12 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 12 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 26 taken 12 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 12 times.
36 end function layer_setup
208 !###############################################################################
209
210
211 !###############################################################################
212 13 subroutine set_hyperparams_dynamic_lno( &
213 this, num_outputs, num_modes, &
214 use_bias, &
215 activation, &
216 kernel_initialiser, bias_initialiser, &
217 verbose &
218 )
219 use athena__activation, only: activation_setup
220 use athena__initialiser, only: get_default_initialiser, initialiser_setup
221 implicit none
222
223 ! Arguments
224 class(dynamic_lno_layer_type), intent(inout) :: this
225 !! Layer instance to configure
226 integer, intent(in) :: num_outputs
227 !! Number of output features
228 integer, intent(in) :: num_modes
229 !! Number of learnable spectral poles
230 logical, intent(in) :: use_bias
231 !! Whether to use a bias term
232 class(base_actv_type), allocatable, intent(in) :: activation
233 !! Activation function object
234 class(base_init_type), allocatable, intent(in) :: &
235 kernel_initialiser, bias_initialiser
236 !! Kernel and bias initialiser objects
237 integer, optional, intent(in) :: verbose
238 !! Verbosity level
239
240 ! Local variables
241 character(len=256) :: buffer
242 !! Buffer for default initialiser lookup
243
244
5/8
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 13 times.
13 this%name = "dynamic_lno"
245 13 this%type = "nop"
246 13 this%input_rank = 1
247 13 this%output_rank = 1
248 13 this%use_bias = use_bias
249 13 this%num_outputs = num_outputs
250 13 this%num_modes = num_modes
251
252
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
13 if(allocated(this%activation)) deallocate(this%activation)
253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if(.not.allocated(activation))then
254 this%activation = activation_setup("none")
255 else
256
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
13 allocate(this%activation, source=activation)
257 end if
258
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
13 if(allocated(this%kernel_init)) deallocate(this%kernel_init)
259
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
13 if(.not.allocated(kernel_initialiser))then
260
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 buffer = get_default_initialiser(this%activation%name)
261
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
✓ Branch 17 taken 12 times.
✗ Branch 18 not taken.
12 this%kernel_init = initialiser_setup(buffer)
262 else
263
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 allocate(this%kernel_init, source=kernel_initialiser)
264 end if
265
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
13 if(allocated(this%bias_init)) deallocate(this%bias_init)
266
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
13 if(.not.allocated(bias_initialiser))then
267 buffer = get_default_initialiser( &
268 this%activation%name, &
269 is_bias=.true. &
270
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 )
271
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 12 times.
✓ Branch 17 taken 12 times.
✗ Branch 18 not taken.
12 this%bias_init = initialiser_setup(buffer)
272 else
273
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
1 if(allocated(this%bias_init)) deallocate(this%bias_init)
274
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 allocate(this%bias_init, source=bias_initialiser)
275 end if
276
277
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if(present(verbose))then
278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if(abs(verbose).gt.0)then
279 write(*,'("dynamic_lno activation: ",A)') &
280 trim(this%activation%name)
281 end if
282 end if
283
284 13 end subroutine set_hyperparams_dynamic_lno
285 !###############################################################################
286
287
288 !###############################################################################
289
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 subroutine init_dynamic_lno(this, input_shape, verbose)
290 !! Initialise parameter storage and output buffers for the layer
291 implicit none
292
293 ! Arguments
294 class(dynamic_lno_layer_type), intent(inout) :: this
295 !! Layer instance to initialise
296 integer, dimension(:), intent(in) :: input_shape
297 !! Input shape used to infer num_inputs
298 integer, optional, intent(in) :: verbose
299 !! Verbosity level
300
301 ! Local variables
302 integer :: num_inputs, k
303 !! Effective fan-in size and pole index
304 integer :: verbose_ = 0
305 !! Effective verbosity level
306
307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(present(verbose)) verbose_ = verbose
308
309 !---------------------------------------------------------------------------
310 ! Set shapes
311 !---------------------------------------------------------------------------
312
4/8
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
12 if(.not.allocated(this%input_shape)) call this%set_shape(input_shape)
313
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%num_inputs = this%input_shape(1)
314
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 12 times.
24 this%output_shape = [this%num_outputs]
315 12 this%num_params = this%get_num_params()
316
317
318 !---------------------------------------------------------------------------
319 ! Allocate learnable parameters
320 !
321 ! params(1): mu learnable poles [num_modes]
322 ! params(2): beta learnable residues [num_modes]
323 ! params(3): W local bypass weights [num_outputs x num_inputs]
324 ! params(4): b bias [num_outputs] (optional)
325 !---------------------------------------------------------------------------
326
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
12 allocate(this%weight_shape(2,3))
327
9/16
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
✓ Branch 21 taken 24 times.
✓ Branch 22 taken 12 times.
36 this%weight_shape(:,1) = [ this%num_modes, 1 ]
328
9/16
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
✓ Branch 21 taken 24 times.
✓ Branch 22 taken 12 times.
36 this%weight_shape(:,2) = [ this%num_modes, 1 ]
329
9/16
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
✓ Branch 21 taken 24 times.
✓ Branch 22 taken 12 times.
36 this%weight_shape(:,3) = [ this%num_outputs, this%num_inputs ]
330
331
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if(this%use_bias)then
332
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 10 times.
20 this%bias_shape = [ this%num_outputs ]
333
16/30
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 10 times.
✓ Branch 21 taken 40 times.
✓ Branch 22 taken 10 times.
✓ Branch 23 taken 40 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 40 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 40 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 40 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 40 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 40 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 40 times.
50 allocate(this%params(4))
334 else
335
16/30
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✓ Branch 21 taken 6 times.
✓ Branch 22 taken 2 times.
✓ Branch 23 taken 6 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 6 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 6 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 6 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 6 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 6 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 6 times.
8 allocate(this%params(3))
336 end if
337
338 ! mu: learnable poles
339
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 12 times.
48 call this%params(1)%allocate([this%num_modes, 1, 1])
340
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 call this%params(1)%set_requires_grad(.true.)
341
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(1)%fix_pointer = .true.
342
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(1)%is_sample_dependent = .false.
343
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(1)%is_temporary = .false.
344
345 ! beta: learnable residues
346
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 12 times.
48 call this%params(2)%allocate([this%num_modes, 1, 1])
347
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 call this%params(2)%set_requires_grad(.true.)
348
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(2)%fix_pointer = .true.
349
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(2)%is_sample_dependent = .false.
350
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(2)%is_temporary = .false.
351
352 ! W: local bypass weights
353
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 12 times.
48 call this%params(3)%allocate([this%num_outputs, this%num_inputs, 1])
354
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 call this%params(3)%set_requires_grad(.true.)
355
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(3)%fix_pointer = .true.
356
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(3)%is_sample_dependent = .false.
357
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
12 this%params(3)%is_temporary = .false.
358
359 12 num_inputs = this%num_inputs
360
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if(this%use_bias)then
361 10 num_inputs = this%num_inputs + 1
362
12/20
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 10 times.
✓ Branch 21 taken 10 times.
✓ Branch 22 taken 10 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 10 times.
✓ Branch 25 taken 20 times.
✓ Branch 26 taken 10 times.
40 call this%params(4)%allocate([this%bias_shape, 1])
363
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 call this%params(4)%set_requires_grad(.true.)
364
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 this%params(4)%fix_pointer = .true.
365
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 this%params(4)%is_sample_dependent = .false.
366
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 this%params(4)%is_temporary = .false.
367 end if
368
369
370 !---------------------------------------------------------------------------
371 ! Initialise learnable parameters
372 !
373 ! Poles: mu_n = n*pi (matches original fixed Laplace frequencies, gives
374 ! the same initial spectral basis as the prior fixed construction)
375 ! Residues: kernel initialiser (small random values)
376 ! W: kernel initialiser
377 ! b: bias initialiser
378 !---------------------------------------------------------------------------
379
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 12 times.
49 do k = 1, this%num_modes
380
6/12
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 37 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 37 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 37 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 37 times.
49 this%params(1)%val(k, 1) = real(k, real32) * pi
381 end do
382 call this%kernel_init%initialise( &
383 120 this%params(2)%val(:,1), &
384 fan_in = this%num_modes, fan_out = this%num_modes, &
385 spacing = [ this%num_modes ] &
386
12/22
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 12 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 12 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 12 times.
✓ Branch 30 taken 12 times.
✓ Branch 31 taken 12 times.
24 )
387 call this%kernel_init%initialise( &
388 120 this%params(3)%val(:,1), &
389 fan_in = num_inputs, fan_out = this%num_outputs, &
390 spacing = [ this%num_outputs ] &
391
12/22
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 12 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 12 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 12 times.
✓ Branch 30 taken 12 times.
✓ Branch 31 taken 12 times.
24 )
392
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if(this%use_bias)then
393 call this%bias_init%initialise( &
394 100 this%params(4)%val(:,1), &
395 fan_in = num_inputs, fan_out = this%num_outputs &
396
10/20
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 10 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 10 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 10 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 10 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 10 times.
10 )
397 end if
398
399
400 !---------------------------------------------------------------------------
401 ! Allocate output arrays
402 !---------------------------------------------------------------------------
403
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
12 if(allocated(this%output)) deallocate(this%output)
404
15/26
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 12 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 12 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 12 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 12 times.
✓ Branch 33 taken 12 times.
✓ Branch 34 taken 12 times.
✓ Branch 35 taken 12 times.
✓ Branch 36 taken 12 times.
36 allocate(this%output(1,1))
405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(this%z(1)%allocated) call this%z(1)%deallocate()
406
407 12 end subroutine init_dynamic_lno
408 !###############################################################################
409
410
411 !###############################################################################
412 function get_bases_dynamic_lno(this) result(bases)
413 !! Rebuild the dynamic Laplace encoder/decoder bases from the current
414 !! learnable pole values (params(1)).
415 !!
416 !! Called at the start of each forward pass so that the computation graph
417 !! always uses up-to-date poles. The rebuilt bases are non-tracked
418 !! (requires_grad = .false.); gradient flow for the residues beta goes
419 !! through the diffstruc * operator, and gradient flow for the bypass
420 !! weights W goes through matmul.
421 !!
422 !! E(mu)[n,j] = exp(-mu_n * t_j), t_j = (j-1)/(n_in-1)
423 !! D(mu)[i,n] = exp(-mu_n * tau_i), tau_i = (i-1)/(n_out-1)
424 implicit none
425
426 ! Arguments
427 class(dynamic_lno_layer_type), intent(in) :: this
428 !! Layer instance providing pole values
429 type(array_type), dimension(2) :: bases
430 !! Encoder and decoder basis tensors rebuilt from poles
431
432 ! Local variables
433 integer :: j, k, i, idx
434 !! Basis-construction loop indices and flattened index
435 real(real32) :: s, t
436 !! Pole value and normalised coordinate
437
438 !---------------------------------------------------------------------------
439 ! Encoder E [num_modes x num_inputs]
440 !---------------------------------------------------------------------------
441 call bases(1)%allocate( [this%num_modes, this%num_inputs, 1] )
442 bases(1)%is_sample_dependent = .false.
443 bases(1)%requires_grad = .false.
444 bases(1)%fix_pointer = .true.
445 bases(1)%is_temporary = .false.
446
447 do j = 1, this%num_inputs
448 if(this%num_inputs .gt. 1)then
449 t = real(j-1, real32) / real(this%num_inputs-1, real32)
450 else
451 t = 0.0_real32
452 end if
453 do k = 1, this%num_modes
454 s = this%params(1)%val(k, 1)
455 idx = k + (j-1) * this%num_modes
456 bases(1)%val(idx, 1) = exp(-s * t)
457 end do
458 end do
459
460 !---------------------------------------------------------------------------
461 ! Decoder D [num_outputs x num_modes]
462 !---------------------------------------------------------------------------
463 call bases(2)%allocate( [this%num_outputs, this%num_modes, 1] )
464 bases(2)%is_sample_dependent = .false.
465 bases(2)%requires_grad = .false.
466 bases(2)%fix_pointer = .true.
467 bases(2)%is_temporary = .false.
468
469 do k = 1, this%num_modes
470 s = this%params(1)%val(k, 1)
471 do i = 1, this%num_outputs
472 if(this%num_outputs .gt. 1)then
473 t = real(i-1, real32) / real(this%num_outputs-1, real32)
474 else
475 t = 0.0_real32
476 end if
477 idx = i + (k-1) * this%num_outputs
478 bases(2)%val(idx, 1) = exp(-s * t)
479 end do
480 end do
481
482 end function get_bases_dynamic_lno
483 !###############################################################################
484
485
486 !###############################################################################
487 1 subroutine print_to_unit_dynamic_lno(this, unit)
488 !! Print dynamic LNO settings and parameters to a unit
489 use coreutils, only: to_upper
490 implicit none
491
492 ! Arguments
493 class(dynamic_lno_layer_type), intent(in) :: this
494 !! Layer instance to print
495 integer, intent(in) :: unit
496 !! Output unit number
497
498 1 write(unit,'(3X,"NUM_INPUTS = ",I0)') this%num_inputs
499 1 write(unit,'(3X,"NUM_OUTPUTS = ",I0)') this%num_outputs
500 1 write(unit,'(3X,"NUM_MODES = ",I0)') this%num_modes
501 1 write(unit,'(3X,"USE_BIAS = ",L1)') this%use_bias
502
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%activation%name .ne. 'none')then
503 1 call this%activation%print_to_unit(unit)
504 end if
505
506 1 write(unit,'("WEIGHTS")')
507
10/18
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 25 taken 2 times.
✓ Branch 26 taken 1 times.
3 write(unit,'(5(E16.8E2))') this%params(1)%val(:,1) ! poles
508
10/18
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 25 taken 2 times.
✓ Branch 26 taken 1 times.
3 write(unit,'(5(E16.8E2))') this%params(2)%val(:,1) ! residues
509
10/18
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 25 taken 12 times.
✓ Branch 26 taken 1 times.
13 write(unit,'(5(E16.8E2))') this%params(3)%val(:,1) ! W
510
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%use_bias)then
511
10/18
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✓ Branch 25 taken 4 times.
✓ Branch 26 taken 1 times.
5 write(unit,'(5(E16.8E2))') this%params(4)%val(:,1) ! b
512 end if
513 1 write(unit,'("END WEIGHTS")')
514
515 1 end subroutine print_to_unit_dynamic_lno
516 !###############################################################################
517
518
519 !###############################################################################
520 1 subroutine read_dynamic_lno(this, unit, verbose)
521 use athena__tools_infile, only: assign_val, assign_vec, move
522 use coreutils, only: to_lower, to_upper, icount
523 use athena__activation, only: read_activation
524 use athena__initialiser, only: initialiser_setup
525 implicit none
526
527 ! Arguments
528 class(dynamic_lno_layer_type), intent(inout) :: this
529 !! Layer instance to populate from file data
530 integer, intent(in) :: unit
531 !! Input unit number
532 integer, optional, intent(in) :: verbose
533 !! Verbosity level
534
535 ! Local variables
536 integer :: stat, verbose_ = 0
537 !! I/O status and effective verbosity level
538 integer :: j, k, c, itmp1, iline
539 !! Loop counters and parser scratch integers
540 integer :: num_inputs, num_outputs, num_modes
541 !! Parsed layer dimensions
542 logical :: use_bias = .true.
543 !! Parsed bias flag
544 character(14) :: kernel_initialiser_name='', bias_initialiser_name=''
545 !! Parsed initialiser names
546 3 class(base_actv_type), allocatable :: activation
547 !! Parsed activation object
548 5 class(base_init_type), allocatable :: kernel_initialiser, bias_initialiser
549 !! Parsed initialiser objects
550 character(256) :: buffer, tag, err_msg
551 !! Input buffer, parsed tag and formatted error message
552 1 real(real32), allocatable, dimension(:) :: data_list
553 !! Temporary storage for flattened parameter blocks
554 integer :: param_line, final_line, num_vals
555 !! Weights-section line markers and current block size
556
557
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(present(verbose)) verbose_ = verbose
558
559 1 iline = 0
560 1 param_line = 0
561 1 final_line = 0
562 13 tag_loop: do
563 14 read(unit,'(A)',iostat=stat) buffer
564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if(stat.ne.0)then
565 write(err_msg,'("file encountered error (EoF?) before END ",A)') &
566 to_upper(this%name)
567 call stop_program(err_msg)
568 return
569 end if
570
2/4
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
14 if(trim(adjustl(buffer)).eq."") cycle tag_loop
571
572
4/6
✓ Branch 3 taken 14 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 13 times.
28 if(trim(adjustl(buffer)).eq."END "//to_upper(trim(this%name)))then
573 1 final_line = iline
574 1 backspace(unit)
575 14 exit tag_loop
576 end if
577 13 iline = iline + 1
578
579
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
13 tag=trim(adjustl(buffer))
580
6/10
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
13 if(scan(buffer,"=").ne.0) tag=trim(tag(:scan(tag,"=")-1))
581
582 26 select case(trim(tag))
583 case("NUM_INPUTS")
584 2 call assign_val(buffer, num_inputs, itmp1)
585 case("NUM_OUTPUTS")
586 2 call assign_val(buffer, num_outputs, itmp1)
587 case("NUM_MODES")
588 2 call assign_val(buffer, num_modes, itmp1)
589 case("USE_BIAS")
590 2 call assign_val(buffer, use_bias, itmp1)
591 case("ACTIVATION")
592 1 iline = iline - 1
593 1 backspace(unit)
594
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
1 activation = read_activation(unit, iline)
595 case("KERNEL_INITIALISER", "KERNEL_INIT", "KERNEL_INITIALIZER")
596 call assign_val(buffer, kernel_initialiser_name, itmp1)
597 case("BIAS_INITIALISER", "BIAS_INIT", "BIAS_INITIALIZER")
598 call assign_val(buffer, bias_initialiser_name, itmp1)
599 case("WEIGHTS")
600 1 kernel_initialiser_name = 'zeros'
601 1 bias_initialiser_name = 'zeros'
602 1 param_line = iline
603 case default
604
3/4
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1 times.
14 if(scan(to_lower(trim(adjustl(buffer))),&
605 'abcdfghijklmnopqrstuvwxyz').eq.0)then
606 7 cycle tag_loop
607
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 elseif(tag(:3).eq.'END')then
608 7 cycle tag_loop
609 end if
610 write(err_msg,'("Unrecognised line in input file: ",A)') &
611 trim(adjustl(buffer))
612 call stop_program(err_msg)
613
8/11
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 7 times.
26 return
614 end select
615 end do tag_loop
616
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
1 kernel_initialiser = initialiser_setup(kernel_initialiser_name)
617
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
1 bias_initialiser = initialiser_setup(bias_initialiser_name)
618
619 call this%set_hyperparams( &
620 num_outputs = num_outputs, &
621 num_modes = num_modes, &
622 use_bias = use_bias, &
623 activation = activation, &
624 kernel_initialiser = kernel_initialiser, &
625 bias_initialiser = bias_initialiser, &
626 verbose = verbose_ &
627 1 )
628
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 call this%init(input_shape=[num_inputs])
629
630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(param_line.eq.0)then
631 write(0,*) "WARNING: WEIGHTS card in " // trim(this%name) // " not found"
632 else
633 1 call move(unit, param_line - iline, iostat=stat)
634
635 ! Read poles (num_modes values)
636 1 num_vals = num_modes
637
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 allocate(data_list(num_vals), source=0._real32)
638 1 c = 1
639 1 k = 1
640
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 do while(c.le.num_vals)
641 1 read(unit,'(A)',iostat=stat) buffer
642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(stat.ne.0) exit
643 1 k = icount(buffer)
644
5/8
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
3 read(buffer,*,iostat=stat) (data_list(j),j=c,c+k-1)
645 1 c = c + k
646 end do
647
15/28
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1 times.
✓ Branch 39 taken 2 times.
✓ Branch 40 taken 1 times.
3 this%params(1)%val(:,1) = data_list
648
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
649
650 ! Read residues (num_modes values)
651 1 num_vals = num_modes
652
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 allocate(data_list(num_vals), source=0._real32)
653 1 c = 1
654 1 k = 1
655
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 do while(c.le.num_vals)
656 1 read(unit,'(A)',iostat=stat) buffer
657
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(stat.ne.0) exit
658 1 k = icount(buffer)
659
5/8
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2 times.
3 read(buffer,*,iostat=stat) (data_list(j),j=c,c+k-1)
660 1 c = c + k
661 end do
662
15/28
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1 times.
✓ Branch 39 taken 2 times.
✓ Branch 40 taken 1 times.
3 this%params(2)%val(:,1) = data_list
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
664
665 ! Read W (num_outputs * num_inputs values)
666 1 num_vals = num_outputs * num_inputs
667
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 allocate(data_list(num_vals), source=0._real32)
668 1 c = 1
669 1 k = 1
670
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 do while(c.le.num_vals)
671 3 read(unit,'(A)',iostat=stat) buffer
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(stat.ne.0) exit
673 3 k = icount(buffer)
674
5/8
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
15 read(buffer,*,iostat=stat) (data_list(j),j=c,c+k-1)
675 3 c = c + k
676 end do
677
15/28
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1 times.
✓ Branch 39 taken 12 times.
✓ Branch 40 taken 1 times.
13 this%params(3)%val(:,1) = data_list
678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
679
680 ! Read b if use_bias
681
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(use_bias)then
682
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 allocate(data_list(num_outputs), source=0._real32)
683 1 c = 1
684 1 k = 1
685
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 do while(c.le.num_outputs)
686 1 read(unit,'(A)',iostat=stat) buffer
687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(stat.ne.0) exit
688 1 k = icount(buffer)
689
5/8
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4 times.
5 read(buffer,*,iostat=stat) (data_list(j),j=c,c+k-1)
690 1 c = c + k
691 end do
692
15/28
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1 times.
✓ Branch 39 taken 4 times.
✓ Branch 40 taken 1 times.
5 this%params(4)%val(:,1) = data_list(1:num_outputs)
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
694 end if
695
696 1 read(unit,'(A)') buffer
697
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 if(trim(adjustl(buffer)).ne."END WEIGHTS")then
698 call stop_program("END WEIGHTS not where expected")
699 return
700 end if
701
702 end if
703
704 1 call move(unit, final_line - iline, iostat=stat)
705 1 read(unit,'(A)') buffer
706
3/6
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
2 if(trim(adjustl(buffer)).ne."END "//to_upper(trim(this%name)))then
707 write(err_msg,'("END ",A," not where expected")') to_upper(this%name)
708 call stop_program(err_msg)
709 1 return
710 end if
711
712
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 end subroutine read_dynamic_lno
713 !###############################################################################
714
715
716 !###############################################################################
717 1 function read_dynamic_lno_layer(unit, verbose) result(layer)
718 !! Read a dynamic LNO layer from file and return it
719 implicit none
720
721 ! Arguments
722 integer, intent(in) :: unit
723 !! Input unit number
724 integer, optional, intent(in) :: verbose
725 !! Verbosity level
726 class(base_layer_type), allocatable :: layer
727 !! Allocated base-layer instance containing the result
728
729 ! Local variables
730 integer :: verbose_ = 0
731 !! Effective verbosity level
732
733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(present(verbose)) verbose_ = verbose
734 allocate(layer, source=dynamic_lno_layer_type( &
735
21/78
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✓ Branch 47 taken 1 times.
✗ Branch 49 not taken.
✓ Branch 50 taken 1 times.
✗ Branch 51 not taken.
✓ Branch 52 taken 1 times.
✗ Branch 53 not taken.
✓ Branch 54 taken 1 times.
✗ Branch 55 not taken.
✓ Branch 56 taken 1 times.
✗ Branch 57 not taken.
✓ Branch 58 taken 1 times.
✗ Branch 59 not taken.
✓ Branch 60 taken 1 times.
✗ Branch 62 not taken.
✓ Branch 63 taken 1 times.
✓ Branch 64 taken 1 times.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✓ Branch 67 taken 1 times.
✓ Branch 69 taken 1 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 1 times.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✓ Branch 74 taken 1 times.
✓ Branch 76 taken 1 times.
✗ Branch 77 not taken.
✓ Branch 78 taken 1 times.
✗ Branch 79 not taken.
✗ Branch 80 not taken.
✓ Branch 81 taken 1 times.
✓ Branch 83 taken 1 times.
✗ Branch 84 not taken.
2 num_outputs=0, num_modes=1))
736 1 call layer%read(unit, verbose=verbose_)
737
738 2 end function read_dynamic_lno_layer
739 !###############################################################################
740
741
742 !###############################################################################
743
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 subroutine forward_dynamic_lno(this, input)
744 !! Forward propagation for the Laplace Neural Operator layer
745 !!
746 !! Computes via pole-residue spectral decomposition:
747 !! v = sigma( D(mu) @ diag(beta) @ E(mu) @ u + W @ u + b )
748 !!
749 !! Bases E(mu) and D(mu) are rebuilt from current poles at each call.
750 !! The element-wise residue scaling uses the diffstruc * broadcast:
751 !! beta [M,1] * encoded [M,batch] -> [M,batch]
752 implicit none
753
754 ! Arguments
755 class(dynamic_lno_layer_type), intent(inout) :: this
756 !! Layer instance to execute
757 class(array_type), dimension(:,:), intent(in) :: input
758 !! Input batch tensor collection
759
760 ! Local variables
761 type(array_type), pointer :: ptr, ptr_spec, ptr_local
762 !! Combined output, spectral-path output and local-path output
763
764
765 ! Spectral pathway: D(mu) @ diag(beta) @ E(mu) @ u
766 ! Uses autodiff-tracked lno_encode/lno_decode for pole gradients
767 !---------------------------------------------------------------------------
768 ptr_spec => lno_encode(input(1,1), this%params(1), &
769
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
4 this%num_inputs, this%num_modes) ! [M, batch]
770
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 ptr_spec => elem_scale(ptr_spec, this%params(2))
771 ! [M, batch] residue scaling
772 8 ptr_spec => lno_decode(ptr_spec, this%params(1), &
773
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 this%num_outputs, this%num_modes) ! [n_out, batch]
774
775 ! Local bypass: W @ u
776 !---------------------------------------------------------------------------
777
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
4 ptr_local => matmul(this%params(3), input(1,1)) ! [n_out, batch]
778
779 ! Combine
780 !---------------------------------------------------------------------------
781 4 ptr => ptr_spec + ptr_local
782
783 ! Add bias
784 !---------------------------------------------------------------------------
785
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(this%use_bias)then
786
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
4 ptr => ptr + this%params(4)
787 end if
788
789 ! Apply activation
790 !---------------------------------------------------------------------------
791
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
4 call this%output(1,1)%zero_grad()
792
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
4 if(trim(this%activation%name) .eq. "none")then
793
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
1 call this%output(1,1)%assign_and_deallocate_source(ptr)
794 else
795 3 call this%z(1)%zero_grad()
796 3 call this%z(1)%assign_and_deallocate_source(ptr)
797 3 this%z(1)%is_temporary = .false.
798 3 ptr => this%activation%apply(this%z(1))
799
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 call this%output(1,1)%assign_and_deallocate_source(ptr)
800 end if
801
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
4 this%output(1,1)%is_temporary = .false.
802
803 4 end subroutine forward_dynamic_lno
804 !###############################################################################
805
806
807 !###############################################################################
808 2 function get_attributes_dynamic_lno(this) result(attributes)
809 !! Return list of dynamic LNO attributes for ONNX export
810 implicit none
811
812 ! Arguments
813 class(dynamic_lno_layer_type), intent(in) :: this
814 !! Instance of the dynamic LNO layer
815 type(onnx_attribute_type), allocatable, dimension(:) :: attributes
816 !! List of attributes for ONNX export
817
818 ! Local variables
819 character(32) :: buffer
820 !! Buffer for integer-to-string conversion
821
822
13/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✓ Branch 21 taken 10 times.
✓ Branch 22 taken 2 times.
✓ Branch 23 taken 10 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 10 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 10 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 10 times.
12 allocate(attributes(5))
823
824 2 write(buffer, '(I0)') this%num_inputs
825 attributes(1) = onnx_attribute_type( &
826
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 name='num_inputs', type='int', val=trim(buffer))
827 2 write(buffer, '(I0)') this%num_outputs
828 attributes(2) = onnx_attribute_type( &
829
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 name='num_outputs', type='int', val=trim(buffer))
830 2 write(buffer, '(I0)') this%num_modes
831 attributes(3) = onnx_attribute_type( &
832
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 name='num_modes', type='int', val=trim(buffer))
833
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(this%use_bias)then
834 2 buffer = '1'
835 else
836 buffer = '0'
837 end if
838 attributes(4) = onnx_attribute_type( &
839
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 name='use_bias', type='int', val=trim(buffer))
840 attributes(5) = onnx_attribute_type( &
841
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
2 name='activation', type='string', val=trim(this%activation%name))
842
843 2 end function get_attributes_dynamic_lno
844 !###############################################################################
845
846
847 !###############################################################################
848 1 subroutine emit_onnx_nodes_dynamic_lno( &
849
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 this, prefix, nodes, num_nodes, max_nodes, inits, num_inits, &
850 max_inits, input_name, is_last_layer, format)
851 !! Emit decomposed standard ONNX nodes for a Dynamic LNO layer.
852 !!
853 !! Decomposes the forward pass v = sigma(D(mu)*diag(beta)*E(mu)*u + W*u + b)
854 !! into: Exp, MatMul, Mul, Add, Transpose, and optional Relu nodes.
855 implicit none
856
857 ! Arguments
858 class(dynamic_lno_layer_type), intent(in) :: this
859 !! Dynamic LNO layer instance
860 character(*), intent(in) :: prefix
861 !! Layer name prefix (e.g. "layer1")
862 type(onnx_node_type), intent(inout), dimension(:) :: nodes
863 !! Node accumulator
864 integer, intent(inout) :: num_nodes
865 !! Node counter
866 integer, intent(in) :: max_nodes
867 !! Node limit
868 type(onnx_initialiser_type), intent(inout), dimension(:) :: inits
869 !! Initialiser accumulator
870 integer, intent(inout) :: num_inits
871 !! Initialiser counter
872 integer, intent(in) :: max_inits
873 !! Initialiser limit
874 character(*), optional, intent(in) :: input_name
875 !! Name of the input tensor (e.g. "input" or previous layer output)
876 logical, optional, intent(in) :: is_last_layer
877 !! Whether this is the last layer in the network
878 integer, optional, intent(in) :: format
879 !! Export format selector
880
881 ! Local variables
882 integer :: j, k, idx, n
883 real(real32) :: s, t
884 1 real(real32), allocatable :: e_args(:), d_args(:)
885 character(128) :: e_args_name, d_args_name, beta_name, w_name, b_name
886 character(128) :: exp_e_out, exp_d_out, trans_in_out
887 character(128) :: mm_e_out, mul_out, mm_d_out, mm_w_out
888 character(128) :: add_out, add_b_out, final_output, output_source
889 integer :: format_
890
891 1 format_ = 1
892
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(present(format)) format_ = format
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(format_ .ne. 2) return
894
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(.not.present(input_name)) return
895
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(.not.present(is_last_layer)) return
896
897 !--------------------------------------------------------------------------
898 ! Build initialiser names
899 !--------------------------------------------------------------------------
900
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(e_args_name, '(A,".E_args")') trim(prefix)
901
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(d_args_name, '(A,".D_args")') trim(prefix)
902
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(beta_name, '(A,".beta")') trim(prefix)
903
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(w_name, '(A,".W")') trim(prefix)
904
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(b_name, '(A,".b")') trim(prefix)
905
906 !--------------------------------------------------------------------------
907 ! Build intermediate tensor names
908 !--------------------------------------------------------------------------
909
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(exp_e_out, '("/",A,"/Exp_output_0")') trim(prefix)
910
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(exp_d_out, '("/",A,"/Exp_1_output_0")') trim(prefix)
911
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(trans_in_out, '("/",A,"/Transpose_output_0")') trim(prefix)
912
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(mm_e_out, '("/",A,"/MatMul_output_0")') trim(prefix)
913
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(mul_out, '("/",A,"/Mul_output_0")') trim(prefix)
914
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(mm_d_out, '("/",A,"/MatMul_1_output_0")') trim(prefix)
915
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(mm_w_out, '("/",A,"/MatMul_2_output_0")') trim(prefix)
916
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(add_out, '("/",A,"/Add_output_0")') trim(prefix)
917
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 write(add_b_out, '("/",A,"/Add_1_output_0")') trim(prefix)
918
919 !--------------------------------------------------------------------------
920 ! Emit ONNX nodes
921 !--------------------------------------------------------------------------
922 ! 1. Exp(E_args) -> E [M, n_in]
923 1 num_nodes = num_nodes + 1
924
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/Exp")') trim(prefix)
925
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'Exp'
926
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(1))
927
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(e_args_name)
928
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
929
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(exp_e_out)
930
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
931
932 ! 2. Exp(D_args) -> D [n_out, M]
933 1 num_nodes = num_nodes + 1
934
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/Exp_1")') trim(prefix)
935
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'Exp'
936
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(1))
937
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(d_args_name)
938
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
939
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(exp_d_out)
940
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
941
942 ! 3. Transpose(input) -> x_t [n_in, batch]
943 call emit_nop_input_transpose(trim(prefix), trim(input_name), nodes, &
944
6/12
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
1 num_nodes, trim(trans_in_out))
945
946 ! 4. MatMul(E, x_t) -> encoded [M, batch]
947 1 num_nodes = num_nodes + 1
948
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/MatMul")') trim(prefix)
949
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'MatMul'
950
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(2))
951
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(exp_e_out)
952
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(2) = trim(trans_in_out)
953
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
954
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(mm_e_out)
955
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
956
957 ! 5. Mul(beta, encoded) -> scaled [M, batch]
958 1 num_nodes = num_nodes + 1
959
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/Mul")') trim(prefix)
960
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'Mul'
961
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(2))
962
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(beta_name)
963
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(2) = trim(mm_e_out)
964
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
965
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(mul_out)
966
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
967
968 ! 6. MatMul(D, scaled) -> spectral [n_out, batch]
969 1 num_nodes = num_nodes + 1
970
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/MatMul_1")') trim(prefix)
971
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'MatMul'
972
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(2))
973
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(exp_d_out)
974
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(2) = trim(mul_out)
975
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
976
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(mm_d_out)
977
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
978
979 ! 7. MatMul(W, x_t) -> local [n_out, batch]
980 1 num_nodes = num_nodes + 1
981
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/MatMul_2")') trim(prefix)
982
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'MatMul'
983
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(2))
984
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(w_name)
985
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(2) = trim(trans_in_out)
986
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
987
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(mm_w_out)
988
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
989
990 ! 8. Add(spectral, local) -> combined [n_out, batch]
991 1 num_nodes = num_nodes + 1
992
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/Add")') trim(prefix)
993
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'Add'
994
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(2))
995
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(mm_d_out)
996
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(2) = trim(mm_w_out)
997
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
998
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(add_out)
999
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
1000
1001 ! 9. Add(combined, bias) -> biased [n_out, batch]
1002
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%use_bias)then
1003 1 num_nodes = num_nodes + 1
1004
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
1 write(nodes(num_nodes)%name, '("/",A,"/Add_1")') trim(prefix)
1005
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%op_type = 'Add'
1006
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%inputs(2))
1007
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(1) = trim(add_out)
1008
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%inputs(2) = trim(b_name)
1009
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
1 allocate(nodes(num_nodes)%outputs(1))
1010
6/12
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
1 nodes(num_nodes)%outputs(1) = trim(add_b_out)
1011
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 nodes(num_nodes)%attributes_json = ''
1012 end if
1013
1014
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%use_bias)then
1015 1 output_source = add_b_out
1016 else
1017 output_source = add_out
1018 end if
1019 call emit_nop_output_tail(trim(prefix), trim(this%activation%name), &
1020
6/12
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 18 not taken.
1 is_last_layer, trim(output_source), nodes, num_nodes, final_output)
1021
1022 !--------------------------------------------------------------------------
1023 ! Emit initialisers
1024 !--------------------------------------------------------------------------
1025
1026 ! W: bypass weights [n_out, n_in] in row-major
1027 1 n = this%num_outputs * this%num_inputs
1028 10 call emit_matrix_initialiser(trim(w_name), this%params(3)%val(:,1), &
1029
14/28
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 1 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 1 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 1 times.
✗ Branch 37 not taken.
✓ Branch 38 taken 1 times.
✓ Branch 41 taken 1 times.
✗ Branch 42 not taken.
1 this%num_outputs, this%num_inputs, inits, num_inits)
1030
1031 ! E_args: -mu*t for encoder [M, n_in] in row-major
1032 1 n = this%num_modes * this%num_inputs
1033
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 allocate(e_args(n))
1034
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 times.
25 do j = 1, this%num_inputs
1035
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if(this%num_inputs .gt. 1)then
1036 24 t = real(j - 1, real32) / real(this%num_inputs - 1, real32)
1037 else
1038 t = 0.0_real32
1039 end if
1040
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 24 times.
169 do k = 1, this%num_modes
1041
6/12
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 144 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 144 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 144 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 144 times.
144 s = this%params(1)%val(k, 1)
1042 144 idx = (k - 1) * this%num_inputs + j
1043
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
168 e_args(idx) = -s * t
1044 end do
1045 end do
1046 call emit_float_initialiser(trim(e_args_name), e_args, &
1047
6/10
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
3 [this%num_modes, this%num_inputs], inits, num_inits)
1048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(e_args)
1049
1050 ! D_args: -mu*tau for decoder [n_out, M] in row-major
1051 1 n = this%num_outputs * this%num_modes
1052
7/14
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1 times.
1 allocate(d_args(n))
1053
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 do k = 1, this%num_modes
1054
6/12
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 6 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 6 times.
6 s = this%params(1)%val(k, 1)
1055
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 6 times.
115 do j = 1, this%num_outputs
1056
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 if(this%num_outputs .gt. 1)then
1057 108 t = real(j - 1, real32) / real(this%num_outputs - 1, real32)
1058 else
1059 t = 0.0_real32
1060 end if
1061 108 idx = (j - 1) * this%num_modes + k
1062
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
114 d_args(idx) = -s * t
1063 end do
1064 end do
1065 call emit_float_initialiser(trim(d_args_name), d_args, &
1066
6/10
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
3 [this%num_outputs, this%num_modes], inits, num_inits)
1067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(d_args)
1068
1069 ! beta: residues [M, 1]
1070 10 call emit_float_initialiser(trim(beta_name), this%params(2)%val(:,1), &
1071
16/30
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 1 times.
✓ Branch 31 taken 2 times.
✓ Branch 32 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 39 not taken.
✓ Branch 40 taken 1 times.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
3 [this%num_modes, 1], inits, num_inits)
1072
1073 ! b: bias [n_out, 1] (if use_bias)
1074
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%use_bias)then
1075 10 call emit_float_initialiser(trim(b_name), this%params(4)%val(:,1), &
1076
16/30
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 1 times.
✓ Branch 31 taken 2 times.
✓ Branch 32 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 39 not taken.
✓ Branch 40 taken 1 times.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
3 [this%num_outputs, 1], inits, num_inits)
1077 end if
1078
1079
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 end subroutine emit_onnx_nodes_dynamic_lno
1080 !###############################################################################
1081
1082
42/91
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✓ Branch 36 taken 22 times.
✓ Branch 37 taken 2 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 22 times.
✓ Branch 40 taken 26 times.
✗ Branch 41 not taken.
✓ Branch 42 taken 22 times.
✓ Branch 43 taken 26 times.
✓ Branch 44 taken 22 times.
✓ Branch 45 taken 48 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 22 times.
✓ Branch 48 taken 28 times.
✓ Branch 49 taken 48 times.
✓ Branch 50 taken 2 times.
✓ Branch 51 taken 48 times.
✓ Branch 52 taken 2 times.
✓ Branch 53 taken 20 times.
✓ Branch 54 taken 4 times.
✓ Branch 55 taken 22 times.
✓ Branch 56 taken 2 times.
✓ Branch 57 taken 86 times.
✓ Branch 58 taken 22 times.
✓ Branch 59 taken 86 times.
✗ Branch 60 not taken.
✓ Branch 61 taken 86 times.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✓ Branch 64 taken 86 times.
✗ Branch 65 not taken.
✓ Branch 66 taken 86 times.
✗ Branch 67 not taken.
✓ Branch 68 taken 86 times.
✗ Branch 69 not taken.
✓ Branch 70 taken 86 times.
✓ Branch 71 taken 24 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 24 times.
✗ Branch 75 not taken.
✓ Branch 77 taken 24 times.
✗ Branch 78 not taken.
✓ Branch 80 taken 24 times.
✓ Branch 81 taken 24 times.
✗ Branch 82 not taken.
✓ Branch 83 taken 24 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 24 times.
✗ Branch 86 not taken.
✓ Branch 87 taken 24 times.
✗ Branch 88 not taken.
✓ Branch 89 taken 24 times.
✗ Branch 90 not taken.
✓ Branch 91 taken 24 times.
✗ Branch 92 not taken.
✓ Branch 93 taken 24 times.
504 end module athena__dynamic_lno_layer
1083