You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
observer: entropy is a function of |x| alone with level sets {±x, ±1/x}, so H(x) ≡ H(1/x) — the entropy channel cannot see sign-flip or reciprocal oscillation #862
entropy_of_num (src/eigenscript.c:257) is H₂(1/(1+|x|)). Two identities follow from the formula alone:
H₂(p) = H₂(1−p), and p(1/x) = 1/(1+1/x) = x/(1+x) = 1 − p(x), so H(x) ≡ H(1/x) exactly.
H reads fabs(num), so H(x) ≡ H(−x).
The level set of every value is therefore {x, −x, 1/x, −1/x}. Any trajectory confined to that set has dH = 0 at every step and is invisible to all six predicates and to report.
H(1000) and H(0.001) agree to ~1e-15 — three orders of magnitude below dh_zero = 0.001.
Reproduction
define a as:
x is 5.0
for i in range of 20:
x is 0 - x # ±5 forever: the simplest possible oscillator
print of ("sign-flip: report=" + (report of x) + " oscillating=" + (str of (oscillating of x)))
return 0
a of 0
define b as:
y is 1000.0
for i in range of 20:
y is 1.0 / y # 1000 <-> 0.001, ratio 1e6
print of ("recip: report=" + (report of y) + " converged=" + (str of (converged of y)))
return 0
b of 0
#422 covers the value channel's sub-deadband oscillation blindness (a flip below dh_zero is not counted). This is the entropy channel, and the mechanism is different: the steps here are enormous, not sub-deadband — they are simply invisible to a magnitude-only, non-injective measure. report_value classifies both cases correctly as oscillating, which is the point: the channel that is wrong is the one every bare predicate, report, and loop while not converged read by default.
Why it matters
README.md:150-157 advertises oscillation detection with a 5.0 / 2.0 alternation. That example works only because |5| ≠ |2| and 5 ≠ 1/2. Move it onto a level set and detection silently inverts. docs/PREDICATES.md:479 already documents the non-monotonicity (entropy peaks at |x| = 1); the non-injectivity is undocumented and has sharper consequences.
Keep entropy as the default but break the x → 1/x symmetry (e.g. sign-aware or signed-log measure).
Document the level sets in PREDICATES.md next to the existing |x| = 1 note, and have report cross-check the value channel before returning a rest band.
Finding
entropy_of_num(src/eigenscript.c:257) isH₂(1/(1+|x|)). Two identities follow from the formula alone:H₂(p) = H₂(1−p), andp(1/x) = 1/(1+1/x) = x/(1+x) = 1 − p(x), soH(x) ≡ H(1/x)exactly.Hreadsfabs(num), soH(x) ≡ H(−x).The level set of every value is therefore
{x, −x, 1/x, −1/x}. Any trajectory confined to that set hasdH = 0at every step and is invisible to all six predicates and toreport.Numerically confirmed at v0.38.0 /
078e759:H(1000)andH(0.001)agree to ~1e-15 — three orders of magnitude belowdh_zero = 0.001.Reproduction
The second case is the worse one: a sequence swinging over six orders of magnitude fires the strongest band.
Distinct from #422
#422covers the value channel's sub-deadband oscillation blindness (a flip belowdh_zerois not counted). This is the entropy channel, and the mechanism is different: the steps here are enormous, not sub-deadband — they are simply invisible to a magnitude-only, non-injective measure.report_valueclassifies both cases correctly asoscillating, which is the point: the channel that is wrong is the one every bare predicate,report, andloop while not convergedread by default.Why it matters
README.md:150-157advertises oscillation detection with a5.0 / 2.0alternation. That example works only because|5| ≠ |2|and5 ≠ 1/2. Move it onto a level set and detection silently inverts.docs/PREDICATES.md:479already documents the non-monotonicity (entropy peaks at|x| = 1); the non-injectivity is undocumented and has sharper consequences.Options
reportand the bare predicates, demoting entropy to an opt-in diagnostic. Note this trades these failures for Observer value channel (report_value) is blind to sub-exponential divergence and sub-deadband oscillation (relative-delta normalization) #422's and observer: report_value classifies monotone CONVERGENCE as 'diverging' (rate > ~0.87) #674's, so it needs the value channel's floor raised first — not a free swap.x → 1/xsymmetry (e.g. sign-aware or signed-log measure).PREDICATES.mdnext to the existing|x| = 1note, and havereportcross-check the value channel before returning a rest band.Related: #422, #294, #412, #735.