6
6
from ._soft_segment import soft_segment_unbounded
7
7
8
8
import numpy as np
9
- import numbers
10
9
11
10
12
11
def activate_formation_block (exported_fields : ExportedFields , ids : np .ndarray ,
@@ -30,24 +29,6 @@ def activate_formation_block(exported_fields: ExportedFields, ids: np.ndarray,
30
29
ids = ids ,
31
30
sigmoid_slope = sigmoid_slope
32
31
)
33
- return sigm
34
-
35
- match BackendTensor .engine_backend :
36
- case AvailableBackends .PYTORCH :
37
- sigm = soft_segment_unbounded_torch (
38
- Z = Z_x ,
39
- edges = scalar_value_at_sp ,
40
- ids = ids ,
41
- sigmoid_slope = sigmoid_slope
42
- )
43
- case AvailableBackends .numpy :
44
- sigm = soft_segment_unbounded_np (
45
- Z = Z_x ,
46
- edges = scalar_value_at_sp ,
47
- ids = ids ,
48
- sigmoid_slope = sigmoid_slope
49
- )
50
-
51
32
return sigm
52
33
53
34
@@ -89,140 +70,3 @@ def _compute_sigmoid(Z_x, scale_0, scale_1, drift_0, drift_1, drift_id, sigmoid_
89
70
for i in range (len (ids )):
90
71
sigm += _compute_sigmoid (Z_x , scalar_0_v [i ], scalar_1_v [i ], drift_0_v [i ], drift_1_v [i ], ids [i ], sigmoid_slope )
91
72
return sigm
92
-
93
-
94
- import torch
95
-
96
-
97
- def soft_segment_unbounded_torch (Z , edges , ids , sigmoid_slope ):
98
- """
99
- Z: (...,) tensor of scalar values
100
- edges: (K-1,) tensor of finite split points [e1, e2, ..., e_{K-1}]
101
- ids: (K,) tensor of the id for each of the K bins
102
- tau: scalar target peak slope m > 0
103
- returns: (...,) tensor of the soft‐assigned id
104
- """
105
- # --- ensure torch tensors on the same device/dtype ---
106
- if not isinstance (Z , torch .Tensor ):
107
- Z = torch .tensor (Z , dtype = torch .float32 , device = edges .device )
108
- if not isinstance (edges , torch .Tensor ):
109
- edges = torch .tensor (edges , dtype = Z .dtype , device = Z .device )
110
- if not isinstance (ids , torch .Tensor ):
111
- ids = torch .tensor (ids , dtype = Z .dtype , device = Z .device )
112
-
113
- # --- 1) per-edge temp: tau_k = jump_k / (4 * m) ---
114
- # jumps = ids[1:] - ids[:-1] # shape (K-1,)
115
-
116
- jumps = torch .abs (ids [1 :] - ids [:- 1 ]) # shape (K-1,)
117
- tau_k = jumps / (4 * sigmoid_slope ) # shape (K-1,)
118
-
119
- # --- 2) first bin (-∞, e1) ---
120
- first = torch .sigmoid ((edges [0 ] - Z ) / tau_k [0 ])[..., None ] # (...,1)
121
-
122
- # --- 3) last bin [e_{K-1}, ∞) ---
123
- last = torch .sigmoid ((Z - edges [- 1 ]) / tau_k [- 1 ])[..., None ] # (...,1)
124
-
125
- # --- 4) middle bins [e_i, e_{i+1}) ---
126
- left = torch .sigmoid ((Z [..., None ] - edges [:- 1 ]) / tau_k [:- 1 ]) # (...,K-2)
127
- right = torch .sigmoid ((Z [..., None ] - edges [1 :]) / tau_k [1 :]) # (...,K-2)
128
- middle = left - right # (...,K-2)
129
-
130
- # --- 5) assemble memberships and weight by ids ---
131
- membership = torch .cat ([first , middle , last ], dim = - 1 ) # (...,K)
132
- # return (membership * ids).sum(dim=-1) # (...,)
133
-
134
- # weighted sum by the ids
135
- ids__sum = (membership * ids ).sum (dim = - 1 )
136
-
137
- # make it at least 2d
138
- ids__sum = ids__sum [None , :]
139
-
140
- return ids__sum
141
-
142
-
143
- import numpy as np
144
-
145
-
146
- def soft_segment_unbounded_np (Z , edges , ids , sigmoid_slope ):
147
- """
148
- Z: array of shape (...,) of scalar values
149
- edges: array of shape (K-1,) of finite split points [e1, e2, ..., e_{K-1}]
150
- ids: array of shape (K,) of the id for each of the K bins
151
- sigmoid_slope: scalar target peak slope m > 0
152
- returns: array of shape (...,) of the soft-assigned id
153
- """
154
- Z = np .asarray (Z )
155
- edges = np .asarray (edges )
156
- ids = np .asarray (ids [::- 1 ])
157
-
158
- # Check if sigmoid function is num or array
159
- match sigmoid_slope :
160
- case np .ndarray ():
161
- membership = _final_faults_segmentation (Z , edges , sigmoid_slope )
162
- case numbers .Number ():
163
- membership = _lith_segmentation (Z , edges , ids , sigmoid_slope )
164
- case _:
165
- raise ValueError ("sigmoid_slope must be a float or an array" )
166
-
167
- ids__sum = np .sum (membership * ids , axis = - 1 )
168
- return np .atleast_2d (ids__sum )
169
-
170
-
171
- def _final_faults_segmentation (Z , edges , sigmoid_slope ):
172
- first = _sigmoid (
173
- scalar_field = Z ,
174
- edges = edges [0 ],
175
- tau_k = 1 / sigmoid_slope
176
- ) # shape (...,)
177
- last = _sigmoid (
178
- scalar_field = Z ,
179
- edges = edges [- 1 ],
180
- tau_k = 1 / sigmoid_slope
181
- )
182
- membership = np .concatenate (
183
- [first [..., None ], last [..., None ]],
184
- axis = - 1
185
- ) # shape (...,K)
186
- return membership
187
-
188
-
189
- def _lith_segmentation (Z , edges , ids , sigmoid_slope ):
190
- # 1) per-edge temperatures τ_k = |Δ_k|/(4·m)
191
- jumps = np .abs (ids [1 :] - ids [:- 1 ]) # shape (K-1,)
192
- tau_k = jumps / float (sigmoid_slope ) # shape (K-1,)
193
- # 2) first bin (-∞, e1) via σ((e1 - Z)/τ₁)
194
- first = _sigmoid (
195
- scalar_field = - Z ,
196
- edges = - edges [0 ],
197
- tau_k = tau_k [0 ]
198
- ) # shape (...,)
199
- # 3) last bin [e_{K-1}, ∞) via σ((Z - e_{K-1})/τ_{K-1})
200
- # last = 1.0 / (1.0 + np.exp(-(Z - edges[-1]) / tau_k[-1])) # shape (...,)
201
- last = _sigmoid (
202
- scalar_field = Z ,
203
- edges = edges [- 1 ],
204
- tau_k = tau_k [- 1 ]
205
- )
206
- # 4) middle bins [e_i, e_{i+1}): σ((Z - e_i)/τ_i) - σ((Z - e_{i+1})/τ_{i+1})
207
- # shape (...,1)
208
- left = _sigmoid (
209
- scalar_field = (Z [..., None ]),
210
- edges = edges [:- 1 ],
211
- tau_k = tau_k [:- 1 ]
212
- )
213
- right = _sigmoid (
214
- scalar_field = (Z [..., None ]),
215
- edges = edges [1 :],
216
- tau_k = tau_k [1 :]
217
- )
218
- middle = left - right # (...,K-2)
219
- # 5) assemble memberships and weight by ids
220
- membership = np .concatenate (
221
- [first [..., None ], middle , last [..., None ]],
222
- axis = - 1
223
- ) # shape (...,K)
224
- return membership
225
-
226
-
227
- def _sigmoid (scalar_field , edges , tau_k ):
228
- return 1.0 / (1.0 + np .exp (- (scalar_field - edges ) / tau_k ))
0 commit comments