using System.Numerics; namespace Minds.FeedbackLimits; /// /// Independent evaluation-boundary arithmetic. No Gojo readers or scalar helpers. /// Fractions, message history and unused requests are retained just as explicitly /// as in the compared Gojo contract; this is not a deliberately weakened baseline. /// public static class ConventionalReference { private readonly record struct Fraction { public BigInteger N { get; } public BigInteger D { get; } public Fraction(BigInteger n, BigInteger d) { if (d.IsZero) throw new DivideByZeroException(); if (d.Sign < 0) { n = -n; d = -d; } var gcd = BigInteger.GreatestCommonDivisor(n, d); N = n / gcd; D = d / gcd; } public static implicit operator Fraction(long n) => new(n, 1); public static Fraction operator +(Fraction a, Fraction b) => new(a.N * b.D + b.N * a.D, a.D * b.D); public static Fraction operator -(Fraction a, Fraction b) => new(a.N * b.D - b.N * a.D, a.D * b.D); public static Fraction operator *(Fraction a, Fraction b) => new(a.N * b.N, a.D * b.D); public static Fraction operator /(Fraction a, Fraction b) => new(a.N * b.D, a.D * b.N); public Fraction Abs() => new(BigInteger.Abs(N), D); public long Truncated => checked((long)(N / D)); public override string ToString() => D.IsOne ? N.ToString() : $"{N}/{D}"; } private sealed class Local(long initial, long ticks, long units) { public long Value = initial, Tension, Applications; public readonly long Ticks = ticks, Units = units; public Fraction Reference = 2 * units; public Fraction? Published, Received, Requested, Whole, Remainder; public int? Latest, Consumed; public Fraction Native => new(Value, Ticks); public Fraction Common => Native / Units; } private sealed record Message(int Source, int Sequence, Fraction Value); public static StudyTrace Run(StudyCase c, IReadOnlyList tape) { var parts = new[] { new Local(c.StartA * c.ATicks, c.ATicks, 1), new Local(c.StartB * c.BUnits * c.BTicks, c.BTicks, c.BUnits) }; var messages = new Dictionary(); var pending = new HashSet(); var events = new List(); var rounds = new List(); Fraction[] priorEvent = [parts[0].Common, parts[1].Common], priorRound = [.. priorEvent]; var publications = 0; var deliveries = 0; var admissions = 0; var drops = 0; var calls = 0; Capture(null, null); Complete(0); for (var index = 0; index < tape.Count; index++) { var e = tape[index]; var p = parts[e.Side]; bool? accepted = null; switch (e.Action) { case TapeAction.Publish: messages.Add(e.Message, new Message(e.Side, e.Message, p.Native)); p.Published = p.Native; pending.Add(e.Message); publications++; break; case TapeAction.Deliver: var m = messages[e.Message]; deliveries++; pending.Remove(e.Message); accepted = p.Latest is null || m.Sequence > p.Latest; if (accepted.Value) { p.Received = m.Value * p.Units / parts[m.Source].Units; p.Latest = m.Sequence; admissions++; } break; case TapeAction.Drop: drops++; pending.Remove(e.Message); break; case TapeAction.Respond: accepted = Respond(p, p.Received ?? throw new InvalidDataException("Missing reference receipt"), c.ResponseDenominator, true); break; case TapeAction.ObserveReference: p.Reference = e.Value; break; case TapeAction.RespondToReference: accepted = Respond(p, p.Reference, 1, false); break; case TapeAction.Skip: break; default: throw new InvalidDataException("Unknown host event"); } Capture(e, accepted); if (index == tape.Count - 1 || tape[index + 1].Round != e.Round) Complete(e.Round); } return new StudyTrace(events, rounds); bool Respond(Local p, Fraction target, long denominator, bool consume) { calls++; p.Requested = (target - p.Native) * p.Ticks / denominator; var delta = p.Requested.Value.Truncated; p.Whole = delta; p.Remainder = p.Requested.Value - delta; if (p.Applications >= c.ApplicationLimit || p.Tension != 0 || consume && p.Consumed == p.Latest) return false; var total = checked(p.Value + p.Tension + delta); p.Value = Math.Max(0, total); p.Tension = Math.Min(0, total); p.Applications++; if (consume) p.Consumed = p.Latest; return true; } void Capture(TapeEvent? e, bool? accepted) { events.Add(Frame(e, accepted, priorEvent)); priorEvent = [parts[0].Common, parts[1].Common]; } void Complete(int round) { rounds.Add(Frame(null, null, priorRound) with { Index = events.Count - 1, Round = round, Action = "Round" }); priorRound = [parts[0].Common, parts[1].Common]; } StudyFrame Frame(TapeEvent? e, bool? accepted, Fraction[] previous) { var a = parts[0].Common; var b = parts[1].Common; var da = a - previous[0]; var db = b - previous[1]; // Formulae are deliberately independent of PairObserver's composition reads. var values = new Dictionary { ["a"] = a.ToString(), ["b"] = b.ToString(), ["mean"] = ((a + b) / 2).ToString(), ["gap"] = (b - a).ToString(), ["da"] = da.ToString(), ["db"] = db.ToString(), ["movement"] = (da.Abs() + db.Abs()).ToString(), ["meanChange"] = ((da + db) / 2).ToString(), ["aReferenceGap"] = (parts[0].Reference - a).ToString(), ["bReferenceGap"] = (parts[1].Reference / parts[1].Units - b).ToString() }; for (var i = 0; i < 2; i++) { var p = parts[i]; var prefix = i == 0 ? "a." : "b."; values[prefix + "actuator"] = p.Value.ToString(); values[prefix + "tension"] = p.Tension.ToString(); values[prefix + "applications"] = p.Applications.ToString(); values[prefix + "remaining"] = (c.ApplicationLimit - p.Applications).ToString(); values[prefix + "reference"] = p.Reference.ToString(); values[prefix + "published"] = p.Published?.ToString() ?? "none"; values[prefix + "received"] = p.Received?.ToString() ?? "none"; values[prefix + "latestSequence"] = p.Latest?.ToString() ?? "none"; values[prefix + "consumedSequence"] = p.Consumed?.ToString() ?? "none"; values[prefix + "requested"] = p.Requested?.ToString() ?? "none"; values[prefix + "whole"] = p.Whole?.ToString() ?? "none"; values[prefix + "fraction"] = p.Remainder?.ToString() ?? "none"; } values["publications"] = publications.ToString(); values["deliveryCalls"] = deliveries.ToString(); values["admissions"] = admissions.ToString(); values["drops"] = drops.ToString(); values["applicationCalls"] = calls.ToString(); values["pending"] = pending.Count.ToString(); return new StudyFrame(events.Count, e?.Round ?? 0, e?.Action.ToString() ?? "Initial", e is null ? "" : e.Side == 0 ? "A" : "B", e?.Message ?? 0, e?.Note ?? "", accepted, values); } } }