GCC Code Coverage Report


Directory: src/athena/
File: src/athena/athena_spectral_filter_layer.f90
Date: 2026-04-15 16:08:59
Exec Total Coverage
Lines: 228 317 71.9%
Functions: 0 0 -%
Branches: 580 1616 35.9%

Line Branch Exec Source
1 module athena__spectral_filter_layer
2 !! Module containing implementation of a Spectral Filter layer
3 !!
4 !! This module implements a spectral filtering layer that applies learnable
5 !! element-wise weights in the frequency domain using a Discrete Cosine
6 !! Transform (DCT-II) basis, followed by an inverse transform back to
7 !! physical space. A local affine bypass is added for expressiveness:
8 !!
9 !! \[ \mathbf{v} = \sigma\!\bigl(
10 !! \underbrace{\boldsymbol{\Phi}^{-1}\,
11 !! \mathrm{diag}(\mathbf{w}_s)\,
12 !! \boldsymbol{\Phi}\,\mathbf{u}}_{\text{spectral filtering}}
13 !! + \underbrace{\mathbf{W}\,\mathbf{u}}_{\text{local}}
14 !! + \mathbf{b}\bigr) \]
15 !!
16 !! where:
17 !! - \(\mathbf{u} \in \mathbb{R}^{n_{in}}\) is the input
18 !! - \(\boldsymbol{\Phi} \in \mathbb{R}^{M \times n_{in}}\) is the
19 !! forward DCT basis,
20 !! \(\Phi_{k,j} = \cos\!\bigl(\pi(k{-}1)(j{-}\tfrac12)/n_{in}\bigr)\)
21 !! - \(\mathrm{diag}(\mathbf{w}_s)\) are learnable per-mode spectral
22 !! filter weights (\(\mathbf{w}_s \in \mathbb{R}^M\))
23 !! - \(\boldsymbol{\Phi}^{-1} \in \mathbb{R}^{n_{out} \times M}\) is
24 !! the inverse DCT basis,
25 !! \(\Phi^{-1}_{i,k} = \cos\!\bigl(\pi(k{-}1)(i{-}\tfrac12)/n_{out}\bigr)\)
26 !! - \(\mathbf{W} \in \mathbb{R}^{n_{out} \times n_{in}}\) are the local
27 !! (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 retained spectral modes
31 !!
32 !! Number of parameters (learnable):
33 !! \(M + n_{out}\,n_{in}\) without bias,
34 !! \(M + n_{out}\,n_{in} + n_{out}\) with bias.
35 use coreutils, only: real32, stop_program, pi
36 use athena__base_layer, only: learnable_layer_type, base_layer_type
37 use athena__misc_types, only: base_actv_type, base_init_type, &
38 onnx_node_type, onnx_initialiser_type, onnx_tensor_type
39 use athena__onnx_nop_utils, only: emit_nop_input_transpose, &
40 emit_nop_output_tail, emit_float_initialiser, emit_matrix_initialiser
41 use diffstruc, only: array_type, matmul, operator(+), operator(*)
42 implicit none
43
44
45 private
46
47 public :: spectral_filter_layer_type
48 public :: read_spectral_filter_layer
49
50
51 type, extends(learnable_layer_type) :: spectral_filter_layer_type
52 !! Type for a spectral filter layer
53 integer :: num_inputs
54 !! Number of inputs
55 integer :: num_outputs
56 !! Number of outputs
57 integer :: num_modes
58 !! Number of retained spectral (cosine) modes
59 type(array_type) :: forward_basis
60 !! Fixed forward DCT basis Phi [num_modes x num_inputs]
61 type(array_type) :: inverse_basis
62 !! Fixed inverse DCT basis Phi_inv [num_outputs x num_modes]
63 type(array_type), dimension(1) :: z
64 !! Temporary array for pre-activation values
65 contains
66 procedure, pass(this) :: get_num_params => get_num_params_spectral_filter
67 procedure, pass(this) :: set_hyperparams => set_hyperparams_spectral_filter
68 procedure, pass(this) :: init => init_spectral_filter
69 procedure, pass(this) :: print_to_unit => print_to_unit_spectral_filter
70 procedure, pass(this) :: read => read_spectral_filter
71
72 procedure, pass(this) :: forward => forward_spectral_filter
73 procedure, pass(this) :: emit_onnx_nodes => &
74 emit_onnx_nodes_spectral_filter
75
76 final :: finalise_spectral_filter
77 end type spectral_filter_layer_type
78
79 interface spectral_filter_layer_type
80 module function layer_setup( &
81 num_outputs, num_modes, num_inputs, use_bias, &
82 activation, &
83 kernel_initialiser, bias_initialiser, verbose &
84 ) result(layer)
85 integer, intent(in) :: num_outputs
86 integer, intent(in) :: num_modes
87 integer, optional, intent(in) :: num_inputs
88 logical, optional, intent(in) :: use_bias
89 class(*), optional, intent(in) :: activation
90 class(*), optional, intent(in) :: kernel_initialiser, bias_initialiser
91 integer, optional, intent(in) :: verbose
92 type(spectral_filter_layer_type) :: layer
93 end function layer_setup
94 end interface spectral_filter_layer_type
95
96
97
98 contains
99
100 !###############################################################################
101 8 subroutine finalise_spectral_filter(this)
102 !! Finalise the spectral filter layer
103 implicit none
104
105 ! Arguments
106 type(spectral_filter_layer_type), intent(inout) :: this
107 !! Layer instance to release
108
109
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if(allocated(this%input_shape)) deallocate(this%input_shape)
110
3/6
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 if(allocated(this%output)) deallocate(this%output)
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if(this%z(1)%allocated) call this%z(1)%deallocate()
112
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if(this%forward_basis%allocated) call this%forward_basis%deallocate()
113
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if(this%inverse_basis%allocated) call this%inverse_basis%deallocate()
114
115 8 end subroutine finalise_spectral_filter
116 !###############################################################################
117
118
119 !###############################################################################
120 9 pure function get_num_params_spectral_filter(this) result(num_params)
121 !! Return the number of learnable parameters for the layer
122 implicit none
123
124 ! Arguments
125 class(spectral_filter_layer_type), intent(in) :: this
126 !! Layer instance
127 integer :: num_params
128 !! Total number of learnable parameters
129
130 ! w_s: num_modes, W: n_out * n_in, b: n_out (optional)
131 num_params = this%num_modes + &
132 9 this%num_outputs * this%num_inputs
133
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if(this%use_bias) num_params = num_params + this%num_outputs
134
135 9 end function get_num_params_spectral_filter
136 !###############################################################################
137
138
139 !###############################################################################
140 9 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 9 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 9 times.
18 ) 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 retained spectral modes
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(spectral_filter_layer_type) :: layer
167 !! Constructed spectral filter layer
168
169 ! Local variables
170 integer :: verbose_ = 0
171 !! Effective verbosity level
172 logical :: use_bias_ = .true.
173 !! Effective bias flag
174 27 class(base_actv_type), allocatable :: activation_
175 !! Materialised activation object
176 9 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 9 times.
9 if(present(verbose)) verbose_ = verbose
180
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
9 if(present(use_bias)) use_bias_ = use_bias
181
182
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
9 if(present(activation))then
183
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 5 times.
✓ Branch 17 taken 5 times.
✗ Branch 18 not taken.
5 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 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9 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 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
9 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 9 )
204
205
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
16 if(present(num_inputs)) call layer%init(input_shape=[num_inputs])
206
207
13/28
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 9 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 9 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 9 times.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 26 taken 9 times.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✓ Branch 29 taken 9 times.
27 end function layer_setup
208 !###############################################################################
209
210
211 !###############################################################################
212 10 subroutine set_hyperparams_spectral_filter( &
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(spectral_filter_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 retained spectral modes
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 9 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 10 times.
10 this%name = "spectral_filter"
245 10 this%type = "spfl"
246 10 this%input_rank = 1
247 10 this%output_rank = 1
248 10 this%use_bias = use_bias
249 10 this%num_outputs = num_outputs
250 10 this%num_modes = num_modes
251
252
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
10 if(allocated(this%activation)) deallocate(this%activation)
253
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(.not.allocated(activation))then
254 this%activation = activation_setup("none")
255 else
256
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 allocate(this%activation, source=activation)
257 end if
258
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
10 if(allocated(this%kernel_init)) deallocate(this%kernel_init)
259
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 if(.not.allocated(kernel_initialiser))then
260
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 buffer = get_default_initialiser(this%activation%name)
261
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 9 times.
✓ Branch 17 taken 9 times.
✗ Branch 18 not taken.
9 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 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
10 if(allocated(this%bias_init)) deallocate(this%bias_init)
266
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 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 9 times.
✗ Branch 2 not taken.
9 )
271
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 9 times.
✓ Branch 17 taken 9 times.
✗ Branch 18 not taken.
9 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 10 times.
✗ Branch 1 not taken.
10 if(present(verbose))then
278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if(abs(verbose).gt.0)then
279 write(*,'("SPECTRAL_FILTER activation: ",A)') &
280 trim(this%activation%name)
281 end if
282 end if
283
284 10 end subroutine set_hyperparams_spectral_filter
285 !###############################################################################
286
287
288 !###############################################################################
289
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 subroutine init_spectral_filter(this, input_shape, verbose)
290 !! Initialise parameter storage, fixed bases and output buffers
291 implicit none
292
293 ! Arguments
294 class(spectral_filter_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, j, k, i, idx
303 !! Effective fan-in size and basis-construction indices
304 integer :: verbose_ = 0
305 !! Effective verbosity level
306
307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(present(verbose)) verbose_ = verbose
308
309 !---------------------------------------------------------------------------
310 ! Set shapes
311 !---------------------------------------------------------------------------
312
4/8
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
9 if(.not.allocated(this%input_shape)) call this%set_shape(input_shape)
313
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%num_inputs = this%input_shape(1)
314
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 9 times.
18 this%output_shape = [this%num_outputs]
315 9 this%num_params = this%get_num_params()
316
317
318 !---------------------------------------------------------------------------
319 ! Allocate learnable parameters
320 !
321 ! params(1): w_s spectral filter weights [num_modes]
322 ! params(2): W local bypass weights [num_outputs x num_inputs]
323 ! params(3): b bias [num_outputs] (optional)
324 !---------------------------------------------------------------------------
325
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
9 allocate(this%weight_shape(2,1))
326
9/16
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 9 times.
✓ Branch 21 taken 18 times.
✓ Branch 22 taken 9 times.
27 this%weight_shape(:,1) = [ this%num_outputs, this%num_inputs ]
327
328
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if(this%use_bias)then
329
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 7 times.
14 this%bias_shape = [ this%num_outputs ]
330
16/30
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 7 times.
✓ Branch 21 taken 21 times.
✓ Branch 22 taken 7 times.
✓ Branch 23 taken 21 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 21 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 21 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 21 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 21 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 21 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 21 times.
28 allocate(this%params(3))
331 else
332
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 4 times.
✓ Branch 22 taken 2 times.
✓ Branch 23 taken 4 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 26 taken 4 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 4 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 4 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 4 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 4 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 4 times.
6 allocate(this%params(2))
333 end if
334
335 ! w_s: spectral filter weights (1D, one per mode)
336
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 9 times.
27 call this%params(1)%allocate([this%num_modes, 1])
337
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 call this%params(1)%set_requires_grad(.true.)
338
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%params(1)%fix_pointer = .true.
339
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%params(1)%is_sample_dependent = .false.
340
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%params(1)%is_temporary = .false.
341
342 ! W: local bypass weights
343
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 6 taken 27 times.
✓ Branch 7 taken 9 times.
36 call this%params(2)%allocate([this%num_outputs, this%num_inputs, 1])
344
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 call this%params(2)%set_requires_grad(.true.)
345
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%params(2)%fix_pointer = .true.
346
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%params(2)%is_sample_dependent = .false.
347
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
9 this%params(2)%is_temporary = .false.
348
349 9 num_inputs = this%num_inputs
350
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if(this%use_bias)then
351 7 num_inputs = this%num_inputs + 1
352
12/20
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 7 times.
✓ Branch 21 taken 7 times.
✓ Branch 22 taken 7 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 7 times.
✓ Branch 25 taken 14 times.
✓ Branch 26 taken 7 times.
28 call this%params(3)%allocate([this%bias_shape, 1])
353
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 call this%params(3)%set_requires_grad(.true.)
354
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 this%params(3)%fix_pointer = .true.
355
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 this%params(3)%is_sample_dependent = .false.
356
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
7 this%params(3)%is_temporary = .false.
357 end if
358
359
360 !---------------------------------------------------------------------------
361 ! Initialise learnable parameters
362 ! Spectral weights initialised to 1 (identity filter), local weights
363 ! and bias via the chosen initialisers.
364 !---------------------------------------------------------------------------
365
10/18
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 9 times.
✓ Branch 24 taken 19 times.
✓ Branch 25 taken 9 times.
28 this%params(1)%val(:,1) = 1.0_real32
366
367 call this%kernel_init%initialise( &
368 90 this%params(2)%val(:,1), &
369 fan_in = num_inputs, fan_out = this%num_outputs, &
370 spacing = [ this%num_outputs ] &
371
12/22
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 9 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 9 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 9 times.
✓ Branch 30 taken 9 times.
✓ Branch 31 taken 9 times.
18 )
372
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 if(this%use_bias)then
373 call this%bias_init%initialise( &
374 70 this%params(3)%val(:,1), &
375 fan_in = num_inputs, fan_out = this%num_outputs &
376
10/20
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 7 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 7 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 7 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 7 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 7 times.
7 )
377 end if
378
379
380 !---------------------------------------------------------------------------
381 ! Build fixed forward DCT basis Phi [num_modes x num_inputs]
382 ! Phi(k,j) = cos( pi * (k-1) * (j - 0.5) / n_in )
383 !---------------------------------------------------------------------------
384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(this%forward_basis%allocated) call this%forward_basis%deallocate()
385 call this%forward_basis%allocate( &
386
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 [this%num_modes, this%num_inputs, 1])
387 9 this%forward_basis%is_sample_dependent = .false.
388 9 this%forward_basis%requires_grad = .false.
389 9 this%forward_basis%fix_pointer = .true.
390 9 this%forward_basis%is_temporary = .false.
391
392
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 9 times.
46 do j = 1, this%num_inputs
393
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 37 times.
124 do k = 1, this%num_modes
394 78 idx = k + (j-1) * this%num_modes
395 312 this%forward_basis%val(idx, 1) = cos( &
396 pi * real(k-1, real32) * &
397 (real(j, real32) - 0.5_real32) / &
398 real(this%num_inputs, real32) &
399
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 78 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 78 times.
115 )
400 end do
401 end do
402
403
404 !---------------------------------------------------------------------------
405 ! Build fixed inverse DCT basis Phi_inv [num_outputs x num_modes]
406 ! Phi_inv(i,k) = cos( pi * (k-1) * (i - 0.5) / n_out )
407 !---------------------------------------------------------------------------
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(this%inverse_basis%allocated) call this%inverse_basis%deallocate()
409 call this%inverse_basis%allocate( &
410
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 [this%num_outputs, this%num_modes, 1])
411 9 this%inverse_basis%is_sample_dependent = .false.
412 9 this%inverse_basis%requires_grad = .false.
413 9 this%inverse_basis%fix_pointer = .true.
414 9 this%inverse_basis%is_temporary = .false.
415
416
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 9 times.
28 do k = 1, this%num_modes
417
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 19 times.
116 do i = 1, this%num_outputs
418 88 idx = i + (k-1) * this%num_outputs
419 352 this%inverse_basis%val(idx, 1) = cos( &
420 pi * real(k-1, real32) * &
421 (real(i, real32) - 0.5_real32) / &
422 real(this%num_outputs, real32) &
423
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 88 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 88 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 88 times.
107 )
424 end do
425 end do
426
427
428 !---------------------------------------------------------------------------
429 ! Allocate output arrays
430 !---------------------------------------------------------------------------
431
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
9 if(allocated(this%output)) deallocate(this%output)
432
15/26
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 9 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 9 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 9 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 9 times.
✓ Branch 33 taken 9 times.
✓ Branch 34 taken 9 times.
✓ Branch 35 taken 9 times.
✓ Branch 36 taken 9 times.
27 allocate(this%output(1,1))
433
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(this%z(1)%allocated) call this%z(1)%deallocate()
434
435 9 end subroutine init_spectral_filter
436 !###############################################################################
437
438
439 !###############################################################################
440 1 subroutine print_to_unit_spectral_filter(this, unit)
441 !! Print spectral filter settings and parameters to a unit
442 use coreutils, only: to_upper
443 implicit none
444
445 ! Arguments
446 class(spectral_filter_layer_type), intent(in) :: this
447 !! Layer instance to print
448 integer, intent(in) :: unit
449 !! Output unit number
450
451 1 write(unit,'(3X,"NUM_INPUTS = ",I0)') this%num_inputs
452 1 write(unit,'(3X,"NUM_OUTPUTS = ",I0)') this%num_outputs
453 1 write(unit,'(3X,"NUM_MODES = ",I0)') this%num_modes
454 1 write(unit,'(3X,"USE_BIAS = ",L1)') this%use_bias
455
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%activation%name .ne. 'none')then
456 1 call this%activation%print_to_unit(unit)
457 end if
458
459 1 write(unit,'("WEIGHTS")')
460
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) ! w_s
461
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(2)%val(:,1) ! W
462
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%use_bias)then
463
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(3)%val(:,1) ! b
464 end if
465 1 write(unit,'("END WEIGHTS")')
466
467 1 end subroutine print_to_unit_spectral_filter
468 !###############################################################################
469
470
471 !###############################################################################
472 1 subroutine read_spectral_filter(this, unit, verbose)
473 use athena__tools_infile, only: assign_val, assign_vec, move
474 use coreutils, only: to_lower, to_upper, icount
475 use athena__activation, only: read_activation
476 use athena__initialiser, only: initialiser_setup
477 implicit none
478
479 ! Arguments
480 class(spectral_filter_layer_type), intent(inout) :: this
481 !! Layer instance to populate from file data
482 integer, intent(in) :: unit
483 !! Input unit number
484 integer, optional, intent(in) :: verbose
485 !! Verbosity level
486
487 ! Local variables
488 integer :: stat, verbose_ = 0
489 !! I/O status and effective verbosity level
490 integer :: j, k, c, itmp1, iline
491 !! Loop counters and parser scratch integers
492 integer :: num_inputs, num_outputs, num_modes
493 !! Parsed layer dimensions
494 logical :: use_bias = .true.
495 !! Parsed bias flag
496 character(14) :: kernel_initialiser_name='', bias_initialiser_name=''
497 !! Parsed initialiser names
498 3 class(base_actv_type), allocatable :: activation
499 !! Parsed activation object
500 5 class(base_init_type), allocatable :: kernel_initialiser, bias_initialiser
501 !! Parsed initialiser objects
502 character(256) :: buffer, tag, err_msg
503 !! Input buffer, parsed tag and formatted error message
504 1 real(real32), allocatable, dimension(:) :: data_list
505 !! Temporary storage for flattened parameter blocks
506 integer :: param_line, final_line, num_vals
507 !! Weights-section line markers and current block size
508
509
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(present(verbose)) verbose_ = verbose
510
511 1 iline = 0
512 1 param_line = 0
513 1 final_line = 0
514 12 tag_loop: do
515 13 read(unit,'(A)',iostat=stat) buffer
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if(stat.ne.0)then
517 write(err_msg,'("file encountered error (EoF?) before END ",A)') &
518 to_upper(this%name)
519 call stop_program(err_msg)
520 return
521 end if
522
2/4
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13 times.
13 if(trim(adjustl(buffer)).eq."") cycle tag_loop
523
524
4/6
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 13 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 12 times.
26 if(trim(adjustl(buffer)).eq."END "//to_upper(trim(this%name)))then
525 1 final_line = iline
526 1 backspace(unit)
527 13 exit tag_loop
528 end if
529 12 iline = iline + 1
530
531
2/4
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
12 tag=trim(adjustl(buffer))
532
6/10
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 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.
12 if(scan(buffer,"=").ne.0) tag=trim(tag(:scan(tag,"=")-1))
533
534 24 select case(trim(tag))
535 case("NUM_INPUTS")
536 2 call assign_val(buffer, num_inputs, itmp1)
537 case("NUM_OUTPUTS")
538 2 call assign_val(buffer, num_outputs, itmp1)
539 case("NUM_MODES")
540 2 call assign_val(buffer, num_modes, itmp1)
541 case("USE_BIAS")
542 2 call assign_val(buffer, use_bias, itmp1)
543 case("ACTIVATION")
544 1 iline = iline - 1
545 1 backspace(unit)
546
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)
547 case("KERNEL_INITIALISER", "KERNEL_INIT", "KERNEL_INITIALIZER")
548 call assign_val(buffer, kernel_initialiser_name, itmp1)
549 case("BIAS_INITIALISER", "BIAS_INIT", "BIAS_INITIALIZER")
550 call assign_val(buffer, bias_initialiser_name, itmp1)
551 case("WEIGHTS")
552 1 kernel_initialiser_name = 'zeros'
553 1 bias_initialiser_name = 'zeros'
554 1 param_line = iline
555 case default
556
3/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
12 if(scan(to_lower(trim(adjustl(buffer))),&
557 'abcdfghijklmnopqrstuvwxyz').eq.0)then
558 6 cycle tag_loop
559
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 elseif(tag(:3).eq.'END')then
560 6 cycle tag_loop
561 end if
562 write(err_msg,'("Unrecognised line in input file: ",A)') &
563 trim(adjustl(buffer))
564 call stop_program(err_msg)
565
8/11
✓ Branch 0 taken 12 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 6 times.
24 return
566 end select
567 end do tag_loop
568
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)
569
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)
570
571 call this%set_hyperparams( &
572 num_outputs = num_outputs, &
573 num_modes = num_modes, &
574 use_bias = use_bias, &
575 activation = activation, &
576 kernel_initialiser = kernel_initialiser, &
577 bias_initialiser = bias_initialiser, &
578 verbose = verbose_ &
579 1 )
580
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 call this%init(input_shape=[num_inputs])
581
582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(param_line.eq.0)then
583 write(0,*) "WARNING: WEIGHTS card in SPECTRAL_FILTER not found"
584 else
585 1 call move(unit, param_line - iline, iostat=stat)
586
587 ! Read w_s (num_modes values)
588
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_modes), source=0._real32)
589 1 c = 1
590 1 k = 1
591
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 do while(c.le.num_modes)
592 1 read(unit,'(A)',iostat=stat) buffer
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(stat.ne.0) exit
594 1 k = icount(buffer)
595
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)
596 1 c = c + k
597 end do
598
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(1:num_modes)
599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
600
601 ! Read W (num_outputs * num_inputs values)
602 1 num_vals = num_outputs * num_inputs
603
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)
604 1 c = 1
605 1 k = 1
606
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 do while(c.le.num_vals)
607 3 read(unit,'(A)',iostat=stat) buffer
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(stat.ne.0) exit
609 3 k = icount(buffer)
610
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)
611 3 c = c + k
612 end do
613
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(2)%val(:,1) = data_list
614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
615
616 ! Read b if use_bias
617
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(use_bias)then
618
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)
619 1 c = 1
620 1 k = 1
621
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 do while(c.le.num_outputs)
622 1 read(unit,'(A)',iostat=stat) buffer
623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(stat.ne.0) exit
624 1 k = icount(buffer)
625
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)
626 1 c = c + k
627 end do
628
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(3)%val(:,1) = data_list(1:num_outputs)
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 deallocate(data_list)
630 end if
631
632 1 read(unit,'(A)') buffer
633
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
634 call stop_program("END WEIGHTS not where expected")
635 return
636 end if
637 end if
638
639 1 call move(unit, final_line - iline, iostat=stat)
640 1 read(unit,'(A)') buffer
641
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
642 write(err_msg,'("END ",A," not where expected")') to_upper(this%name)
643 call stop_program(err_msg)
644 1 return
645 end if
646
647
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_spectral_filter
648 !###############################################################################
649
650
651 !###############################################################################
652 1 function read_spectral_filter_layer(unit, verbose) result(layer)
653 !! Read a spectral filter layer from file and return it
654 implicit none
655
656 ! Arguments
657 integer, intent(in) :: unit
658 !! Input unit number
659 integer, optional, intent(in) :: verbose
660 !! Verbosity level
661 class(base_layer_type), allocatable :: layer
662 !! Allocated base-layer instance containing the result
663
664 ! Local variables
665 integer :: verbose_ = 0
666 !! Effective verbosity level
667
668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(present(verbose)) verbose_ = verbose
669 allocate(layer, source=spectral_filter_layer_type( &
670
33/102
✗ 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.
✗ Branch 86 not taken.
✓ Branch 87 taken 1 times.
✗ Branch 88 not taken.
✓ Branch 89 taken 1 times.
✗ Branch 90 not taken.
✓ Branch 91 taken 1 times.
✗ Branch 92 not taken.
✓ Branch 93 taken 1 times.
✗ Branch 94 not taken.
✓ Branch 95 taken 1 times.
✗ Branch 96 not taken.
✓ Branch 97 taken 1 times.
✗ Branch 99 not taken.
✓ Branch 100 taken 1 times.
✗ Branch 101 not taken.
✓ Branch 102 taken 1 times.
✗ Branch 103 not taken.
✓ Branch 104 taken 1 times.
✗ Branch 105 not taken.
✓ Branch 106 taken 1 times.
✗ Branch 107 not taken.
✓ Branch 108 taken 1 times.
✗ Branch 109 not taken.
✓ Branch 110 taken 1 times.
2 num_outputs=0, num_modes=1))
671 1 call layer%read(unit, verbose=verbose_)
672
673 2 end function read_spectral_filter_layer
674 !###############################################################################
675
676
677 !###############################################################################
678
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 subroutine forward_spectral_filter(this, input)
679 !! Forward propagation for the spectral filter layer
680 !!
681 !! Computes:
682 !! v = sigma( Phi_inv @ diag(w_s) @ Phi @ u + W @ u + b )
683 !!
684 !! The element-wise spectral filtering is performed via the * operator
685 !! between the spectral weights (non-sample-dependent) and the spectral
686 !! coefficients (sample-dependent).
687 implicit none
688
689 ! Arguments
690 class(spectral_filter_layer_type), intent(inout) :: this
691 !! Layer instance to execute
692 class(array_type), dimension(:,:), intent(in) :: input
693 !! Input batch tensor collection
694
695 ! Local variables
696 type(array_type), pointer :: ptr, ptr_spec, ptr_local
697 !! Combined output, spectral-path output and local-path output
698
699
700 ! Spectral pathway: Phi_inv @ (w_s * (Phi @ u))
701 !---------------------------------------------------------------------------
702
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 ptr_spec => matmul(this%forward_basis, input(1,1)) ! [M, batch]
703
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 ptr_spec => this%params(1) * ptr_spec ! element-wise filter
704 1 ptr_spec => matmul(this%inverse_basis, ptr_spec) ! [n_out, batch]
705
706 ! Local bypass: W @ u
707 !---------------------------------------------------------------------------
708
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 ptr_local => matmul(this%params(2), input(1,1)) ! [n_out, batch]
709
710 ! Combine
711 !---------------------------------------------------------------------------
712 1 ptr => ptr_spec + ptr_local
713
714 ! Add bias
715 !---------------------------------------------------------------------------
716
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(this%use_bias)then
717
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 ptr => ptr + this%params(3)
718 end if
719
720 ! Apply activation
721 !---------------------------------------------------------------------------
722
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)%zero_grad()
723
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 if(trim(this%activation%name) .eq. "none")then
724
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)
725 else
726 call this%z(1)%zero_grad()
727 call this%z(1)%assign_and_deallocate_source(ptr)
728 this%z(1)%is_temporary = .false.
729 ptr => this%activation%apply(this%z(1))
730 call this%output(1,1)%assign_and_deallocate_source(ptr)
731 end if
732
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 this%output(1,1)%is_temporary = .false.
733
734 1 end subroutine forward_spectral_filter
735 !###############################################################################
736
737
738 !###############################################################################
739 subroutine emit_onnx_nodes_spectral_filter( &
740 this, prefix, nodes, num_nodes, max_nodes, inits, num_inits, &
741 max_inits, input_name, is_last_layer, format)
742 !! Emit decomposed standard ONNX nodes for a Spectral Filter layer.
743 !!
744 !! Forward: v = sigma(w_s * u + W * u + b)
745 implicit none
746
747 ! Arguments
748 class(spectral_filter_layer_type), intent(in) :: this
749 !! Spectral filter layer instance
750 character(*), intent(in) :: prefix
751 !! Layer name prefix
752 type(onnx_node_type), intent(inout), dimension(:) :: nodes
753 !! Node accumulator
754 integer, intent(inout) :: num_nodes
755 !! Node counter
756 integer, intent(in) :: max_nodes
757 !! Node limit
758 type(onnx_initialiser_type), intent(inout), dimension(:) :: inits
759 !! Initialiser accumulator
760 integer, intent(inout) :: num_inits
761 !! Initialiser counter
762 integer, intent(in) :: max_inits
763 !! Initialiser limit
764 character(*), optional, intent(in) :: input_name
765 !! Name of the input tensor
766 logical, optional, intent(in) :: is_last_layer
767 !! Whether this is the last layer
768 integer, optional, intent(in) :: format
769 !! Export format selector
770
771 ! Local variables
772 integer :: n
773 character(128) :: ws_name, w_name, b_name
774 character(128) :: trans_in_out, mm_w_out, mul_out
775 character(128) :: add_out, add_b_out, final_output, output_source
776 integer :: format_
777
778 format_ = 1
779 if(present(format)) format_ = format
780 if(format_ .ne. 2) return
781 if(.not.present(input_name)) return
782 if(.not.present(is_last_layer)) return
783
784 write(ws_name, '(A,".w_s")') trim(prefix)
785 write(w_name, '(A,".W")') trim(prefix)
786 write(b_name, '(A,".b")') trim(prefix)
787
788 write(trans_in_out, '("/",A,"/Transpose_output_0")') trim(prefix)
789 write(mm_w_out, '("/",A,"/MatMul_output_0")') trim(prefix)
790 write(mul_out, '("/",A,"/Mul_output_0")') trim(prefix)
791 write(add_out, '("/",A,"/Add_output_0")') trim(prefix)
792 write(add_b_out, '("/",A,"/Add_1_output_0")') trim(prefix)
793
794 ! Transpose(input)
795 call emit_nop_input_transpose(trim(prefix), trim(input_name), nodes, &
796 num_nodes, trim(trans_in_out))
797
798 ! Mul(w_s, x_t)
799 num_nodes = num_nodes + 1
800 write(nodes(num_nodes)%name, '("/",A,"/Mul")') trim(prefix)
801 nodes(num_nodes)%op_type = 'Mul'
802 allocate(nodes(num_nodes)%inputs(2))
803 nodes(num_nodes)%inputs(1) = trim(ws_name)
804 nodes(num_nodes)%inputs(2) = trim(trans_in_out)
805 allocate(nodes(num_nodes)%outputs(1))
806 nodes(num_nodes)%outputs(1) = trim(mul_out)
807 nodes(num_nodes)%attributes_json = ''
808
809 ! MatMul(W, x_t)
810 num_nodes = num_nodes + 1
811 write(nodes(num_nodes)%name, '("/",A,"/MatMul")') trim(prefix)
812 nodes(num_nodes)%op_type = 'MatMul'
813 allocate(nodes(num_nodes)%inputs(2))
814 nodes(num_nodes)%inputs(1) = trim(w_name)
815 nodes(num_nodes)%inputs(2) = trim(trans_in_out)
816 allocate(nodes(num_nodes)%outputs(1))
817 nodes(num_nodes)%outputs(1) = trim(mm_w_out)
818 nodes(num_nodes)%attributes_json = ''
819
820 ! Add(filtered, local)
821 num_nodes = num_nodes + 1
822 write(nodes(num_nodes)%name, '("/",A,"/Add")') trim(prefix)
823 nodes(num_nodes)%op_type = 'Add'
824 allocate(nodes(num_nodes)%inputs(2))
825 nodes(num_nodes)%inputs(1) = trim(mul_out)
826 nodes(num_nodes)%inputs(2) = trim(mm_w_out)
827 allocate(nodes(num_nodes)%outputs(1))
828 nodes(num_nodes)%outputs(1) = trim(add_out)
829 nodes(num_nodes)%attributes_json = ''
830
831 ! Add(combined, bias)
832 if(this%use_bias)then
833 num_nodes = num_nodes + 1
834 write(nodes(num_nodes)%name, '("/",A,"/Add_1")') trim(prefix)
835 nodes(num_nodes)%op_type = 'Add'
836 allocate(nodes(num_nodes)%inputs(2))
837 nodes(num_nodes)%inputs(1) = trim(add_out)
838 nodes(num_nodes)%inputs(2) = trim(b_name)
839 allocate(nodes(num_nodes)%outputs(1))
840 nodes(num_nodes)%outputs(1) = trim(add_b_out)
841 nodes(num_nodes)%attributes_json = ''
842 end if
843
844 if(this%use_bias)then
845 output_source = add_b_out
846 else
847 output_source = add_out
848 end if
849 call emit_nop_output_tail(trim(prefix), trim(this%activation%name), &
850 is_last_layer, trim(output_source), nodes, num_nodes, final_output)
851
852 ! Initialisers
853 ! w_s: spectral weights [M, 1]
854 call emit_float_initialiser(trim(ws_name), this%params(1)%val(:,1), &
855 [this%num_modes, 1], inits, num_inits)
856
857 ! W: bypass weights [n_out, n_in] in row-major
858 n = this%num_outputs * this%num_inputs
859 call emit_matrix_initialiser(trim(w_name), this%params(2)%val(:,1), &
860 this%num_outputs, this%num_inputs, inits, num_inits)
861
862 ! b: bias [n_out, 1]
863 if(this%use_bias)then
864 call emit_float_initialiser(trim(b_name), this%params(3)%val(:,1), &
865 [this%num_outputs, 1], inits, num_inits)
866 end if
867
868 end subroutine emit_onnx_nodes_spectral_filter
869 !###############################################################################
870
871
58/115
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 12 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 10 times.
✓ Branch 37 taken 2 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 10 times.
✓ Branch 40 taken 8 times.
✗ Branch 41 not taken.
✓ Branch 42 taken 10 times.
✓ Branch 43 taken 8 times.
✓ Branch 44 taken 10 times.
✓ Branch 45 taken 18 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 10 times.
✓ Branch 48 taken 10 times.
✓ Branch 49 taken 18 times.
✓ Branch 50 taken 2 times.
✓ Branch 51 taken 18 times.
✓ Branch 52 taken 2 times.
✓ Branch 53 taken 8 times.
✓ Branch 54 taken 4 times.
✓ Branch 55 taken 10 times.
✓ Branch 56 taken 2 times.
✓ Branch 57 taken 28 times.
✓ Branch 58 taken 10 times.
✓ Branch 59 taken 28 times.
✗ Branch 60 not taken.
✓ Branch 61 taken 28 times.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✓ Branch 64 taken 28 times.
✗ Branch 65 not taken.
✓ Branch 66 taken 28 times.
✗ Branch 67 not taken.
✓ Branch 68 taken 28 times.
✗ Branch 69 not taken.
✓ Branch 70 taken 28 times.
✓ Branch 71 taken 12 times.
✗ Branch 72 not taken.
✓ Branch 74 taken 12 times.
✗ Branch 75 not taken.
✓ Branch 77 taken 12 times.
✗ Branch 78 not taken.
✓ Branch 80 taken 10 times.
✓ Branch 81 taken 2 times.
✓ Branch 82 taken 10 times.
✓ Branch 83 taken 2 times.
✗ Branch 84 not taken.
✓ Branch 85 taken 12 times.
✗ Branch 86 not taken.
✓ Branch 87 taken 12 times.
✗ Branch 88 not taken.
✓ Branch 89 taken 12 times.
✗ Branch 90 not taken.
✓ Branch 91 taken 12 times.
✓ Branch 92 taken 10 times.
✓ Branch 93 taken 2 times.
✓ Branch 94 taken 10 times.
✓ Branch 95 taken 2 times.
✗ Branch 96 not taken.
✓ Branch 97 taken 12 times.
✗ Branch 98 not taken.
✓ Branch 99 taken 12 times.
✗ Branch 100 not taken.
✓ Branch 101 taken 12 times.
✗ Branch 102 not taken.
✓ Branch 103 taken 12 times.
✓ Branch 104 taken 12 times.
✓ Branch 105 taken 12 times.
✗ Branch 106 not taken.
✓ Branch 107 taken 12 times.
✗ Branch 108 not taken.
✓ Branch 109 taken 12 times.
✗ Branch 110 not taken.
✓ Branch 111 taken 12 times.
✗ Branch 112 not taken.
✓ Branch 113 taken 12 times.
✗ Branch 114 not taken.
✓ Branch 115 taken 12 times.
✗ Branch 116 not taken.
✓ Branch 117 taken 12 times.
196 end module athena__spectral_filter_layer
872