From 28af6b67574c0094630e908443a6b492d91e9670 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:30:11 +0000 Subject: [PATCH 1/4] Implement incremental conditional fast path and adaptive pending update indexing Agent-Logs-Url: https://github.com/DanexCodr/Coderive/sessions/e09efce3-65e4-4b52-b570-1f833e7bbc72 Co-authored-by: DanexCodr <216312766+DanexCodr@users.noreply.github.com> --- .../demo/src/main/test/lazyloop/LazyLoop.cod | 71 +++++++++++ src/main/java/cod/range/NaturalArray.java | 92 ++++++++++++-- .../cod/range/formula/ConditionalFormula.java | 119 ++++++++++++++---- 3 files changed, 243 insertions(+), 39 deletions(-) diff --git a/src/main/cod/demo/src/main/test/lazyloop/LazyLoop.cod b/src/main/cod/demo/src/main/test/lazyloop/LazyLoop.cod index 4b8fa6a5..7f1e50a4 100644 --- a/src/main/cod/demo/src/main/test/lazyloop/LazyLoop.cod +++ b/src/main/cod/demo/src/main/test/lazyloop/LazyLoop.cod @@ -303,6 +303,77 @@ out("arrB[600] == 1200 is {d}") // Should be true out("mixedArr[50] = " + mixedArr[50] + " (should be 'middle')") out("mixedArr[27] = " + mixedArr[27] + " (should be 'range')") out("mixedArr[75] = " + mixedArr[75] + " (should be 75)") + + out() + out("15. High-branch conditional fast-path stress:") + manyBranches : [int] = [0 to 1Qi] + for i of [0 to 1Qi] { + if i % 53 == 0 { manyBranches[i] = 53 } + elif i % 52 == 0 { manyBranches[i] = 52 } + elif i % 51 == 0 { manyBranches[i] = 51 } + elif i % 50 == 0 { manyBranches[i] = 50 } + elif i % 49 == 0 { manyBranches[i] = 49 } + elif i % 48 == 0 { manyBranches[i] = 48 } + elif i % 47 == 0 { manyBranches[i] = 47 } + elif i % 46 == 0 { manyBranches[i] = 46 } + elif i % 45 == 0 { manyBranches[i] = 45 } + elif i % 44 == 0 { manyBranches[i] = 44 } + elif i % 43 == 0 { manyBranches[i] = 43 } + elif i % 42 == 0 { manyBranches[i] = 42 } + elif i % 41 == 0 { manyBranches[i] = 41 } + elif i % 40 == 0 { manyBranches[i] = 40 } + elif i % 39 == 0 { manyBranches[i] = 39 } + elif i % 38 == 0 { manyBranches[i] = 38 } + elif i % 37 == 0 { manyBranches[i] = 37 } + elif i % 36 == 0 { manyBranches[i] = 36 } + elif i % 35 == 0 { manyBranches[i] = 35 } + elif i % 34 == 0 { manyBranches[i] = 34 } + elif i % 33 == 0 { manyBranches[i] = 33 } + elif i % 32 == 0 { manyBranches[i] = 32 } + elif i % 31 == 0 { manyBranches[i] = 31 } + elif i % 30 == 0 { manyBranches[i] = 30 } + elif i % 29 == 0 { manyBranches[i] = 29 } + elif i % 28 == 0 { manyBranches[i] = 28 } + elif i % 27 == 0 { manyBranches[i] = 27 } + elif i % 26 == 0 { manyBranches[i] = 26 } + elif i % 25 == 0 { manyBranches[i] = 25 } + elif i % 24 == 0 { manyBranches[i] = 24 } + elif i % 23 == 0 { manyBranches[i] = 23 } + elif i % 22 == 0 { manyBranches[i] = 22 } + elif i % 21 == 0 { manyBranches[i] = 21 } + elif i % 20 == 0 { manyBranches[i] = 20 } + elif i % 19 == 0 { manyBranches[i] = 19 } + elif i % 18 == 0 { manyBranches[i] = 18 } + elif i % 17 == 0 { manyBranches[i] = 17 } + elif i % 16 == 0 { manyBranches[i] = 16 } + elif i % 15 == 0 { manyBranches[i] = 15 } + elif i % 14 == 0 { manyBranches[i] = 14 } + elif i % 13 == 0 { manyBranches[i] = 13 } + elif i % 12 == 0 { manyBranches[i] = 12 } + elif i % 11 == 0 { manyBranches[i] = 11 } + elif i % 10 == 0 { manyBranches[i] = 10 } + elif i % 9 == 0 { manyBranches[i] = 9 } + elif i % 8 == 0 { manyBranches[i] = 8 } + elif i % 7 == 0 { manyBranches[i] = 7 } + elif i % 6 == 0 { manyBranches[i] = 6 } + elif i % 5 == 0 { manyBranches[i] = 5 } + elif i % 4 == 0 { manyBranches[i] = 4 } + else { manyBranches[i] = 1 } + } + out("manyBranches[106] = " + manyBranches[106] + " (should be 53)") + out("manyBranches[104] = " + manyBranches[104] + " (should be 52)") + out("manyBranches[97] = " + manyBranches[97] + " (should be 1)") + + out() + out("16. Pending updates scaling + precedence:") + pendingScale := [0 to 10K] + for i of [0 to 199] { + pendingScale[i to 10K by 100] = i + } + out("pendingScale[500] = " + pendingScale[500] + " (should be 100)") + out("pendingScale[150] = " + pendingScale[150] + " (should be 150)") + out("pendingScale[250] = " + pendingScale[250] + " (should be 150)") + out("pendingScale[199] = " + pendingScale[199] + " (should be 199)") out() out("=== All tests completed ===") diff --git a/src/main/java/cod/range/NaturalArray.java b/src/main/java/cod/range/NaturalArray.java index b2ae1617..0ea3bd96 100644 --- a/src/main/java/cod/range/NaturalArray.java +++ b/src/main/java/cod/range/NaturalArray.java @@ -67,7 +67,10 @@ public class NaturalArray { private Map computedCache = new HashMap(); // Pending updates for lazy assignment + private static final int PENDING_UPDATES_TREE_THRESHOLD = 100; private List pendingUpdates = new ArrayList(); + private NavigableMap> pendingUpdatesByStart = null; + private long nextPendingUpdateOrder = 0L; private boolean hasPendingUpdates = false; // Output cache @@ -214,15 +217,18 @@ public ProcessedRange merge(ProcessedRange other) { private static class PendingRangeUpdate implements Comparable { final ProcessedRange range; final Object value; + final long order; - PendingRangeUpdate(Object spec, Object value) { + PendingRangeUpdate(Object spec, Object value, long order) { this.range = new ProcessedRange(spec); // Process ONCE this.value = value; + this.order = order; } - PendingRangeUpdate(ProcessedRange range, Object value) { + PendingRangeUpdate(ProcessedRange range, Object value, long order) { this.range = range; this.value = value; + this.order = order; } boolean contains(long index) { @@ -1028,8 +1034,7 @@ public void setRange(Object range, Object value) { } try { - pendingUpdates.add(new PendingRangeUpdate(range, value)); - hasPendingUpdates = true; + registerPendingUpdate(new PendingRangeUpdate(range, value, nextPendingUpdateOrder++)); if (!isMutable) { becomeMutable(); @@ -1098,9 +1103,8 @@ public void setMultiRange(Object multiRange, Object value) { if (range == null) { throw new InternalError("Null range in MultiRangeSpec"); } - pendingUpdates.add(new PendingRangeUpdate(range, value)); + registerPendingUpdate(new PendingRangeUpdate(range, value, nextPendingUpdateOrder++)); } - hasPendingUpdates = true; if (!isMutable) { becomeMutable(); @@ -1127,16 +1131,76 @@ private void applyPendingUpdatesForIndex(long index) { if (!hasPendingUpdates || pendingUpdates.isEmpty()) { return; } - + + PendingRangeUpdate resolvedUpdate = resolvePendingUpdateForIndex(index); + if (resolvedUpdate == null) { + return; + } + + if (cache == null) { + cache = new HashMap(); + } + cache.put(index, resolvedUpdate.value); + invalidateRecentCache(index); + } + + private void registerPendingUpdate(PendingRangeUpdate update) { + pendingUpdates.add(update); + hasPendingUpdates = true; + + if (pendingUpdatesByStart != null) { + addPendingUpdateToTree(update); + return; + } + + if (pendingUpdates.size() >= PENDING_UPDATES_TREE_THRESHOLD) { + convertPendingUpdatesToTreeIndex(); + } + } + + private void addPendingUpdateToTree(PendingRangeUpdate update) { + if (pendingUpdatesByStart == null) { + pendingUpdatesByStart = new TreeMap>(); + } + List updatesAtStart = pendingUpdatesByStart.get(update.range.start); + if (updatesAtStart == null) { + updatesAtStart = new ArrayList(); + pendingUpdatesByStart.put(update.range.start, updatesAtStart); + } + updatesAtStart.add(update); + } + + private void convertPendingUpdatesToTreeIndex() { + pendingUpdatesByStart = new TreeMap>(); for (PendingRangeUpdate update : pendingUpdates) { - if (update.contains(index)) { - if (cache == null) { - cache = new HashMap(); + addPendingUpdateToTree(update); + } + } + + private PendingRangeUpdate resolvePendingUpdateForIndex(long index) { + if (pendingUpdatesByStart == null) { + for (int i = pendingUpdates.size() - 1; i >= 0; i--) { + PendingRangeUpdate update = pendingUpdates.get(i); + if (update.contains(index)) { + return update; + } + } + return null; + } + + PendingRangeUpdate winner = null; + NavigableMap> candidatesByStart = pendingUpdatesByStart.headMap(index, true); + for (List updatesAtStart : candidatesByStart.values()) { + for (PendingRangeUpdate candidate : updatesAtStart) { + if (!candidate.contains(index)) { + continue; + } + if (winner == null || candidate.order > winner.order) { + winner = candidate; } - cache.put(index, update.value); - invalidateRecentCache(index); } } + return winner; } public void commitUpdates() { @@ -1166,7 +1230,7 @@ public int compare(PendingRangeUpdate a, PendingRangeUpdate b) { } else if (canMerge(current, update)) { // Extend current range ProcessedRange mergedRange = current.range.merge(update.range); - current = new PendingRangeUpdate(mergedRange, current.value); + current = new PendingRangeUpdate(mergedRange, current.value, current.order); } else { merged.add(current); current = update; @@ -1180,6 +1244,7 @@ public int compare(PendingRangeUpdate a, PendingRangeUpdate b) { } pendingUpdates.clear(); + pendingUpdatesByStart = null; hasPendingUpdates = false; } @@ -1688,6 +1753,7 @@ public int getPendingUpdateCount() { public void discardUpdates() { pendingUpdates.clear(); + pendingUpdatesByStart = null; hasPendingUpdates = false; } diff --git a/src/main/java/cod/range/formula/ConditionalFormula.java b/src/main/java/cod/range/formula/ConditionalFormula.java index 1fd4c284..0931857b 100644 --- a/src/main/java/cod/range/formula/ConditionalFormula.java +++ b/src/main/java/cod/range/formula/ConditionalFormula.java @@ -9,12 +9,14 @@ import java.util.*; public class ConditionalFormula { + private static final int MAX_FAST_PATH_EXPR_NODES = 4096; + public final long start; public final long end; public final String indexVar; private final Expr unifiedExpression; - private final boolean usesUnifiedExpression; + private final boolean hasFastPathExpression; private final List conditions; private final List> branchStatements; @@ -36,9 +38,9 @@ public ConditionalFormula(long start, long end, String indexVar, this.newerFormula = null; this.olderFormula = null; - Expr built = tryBuildUnifiedExpression(); + Expr built = buildUnifiedExpressionIncremental(); this.unifiedExpression = built; - this.usesUnifiedExpression = built != null; + this.hasFastPathExpression = built != null; } private ConditionalFormula(long start, long end, String indexVar, @@ -54,7 +56,7 @@ private ConditionalFormula(long start, long end, String indexVar, this.branchStatements = new ArrayList>(); this.elseStatements = new ArrayList(); this.unifiedExpression = null; - this.usesUnifiedExpression = false; + this.hasFastPathExpression = false; } public static ConditionalFormula compose(ConditionalFormula newerFormula, ConditionalFormula olderFormula) { @@ -80,16 +82,16 @@ public Object evaluate(long index, Evaluator evaluator, ExecutionContext context } ExecutionContext evalCtx = context.copyWithVariable(indexVar, index, null); - if (usesUnifiedExpression) { + if (hasFastPathExpression) { try { return evaluator.evaluate(unifiedExpression, evalCtx); } catch (ProgramError e) { - return evaluateLegacy(evalCtx, evaluator); + return interpretiveEvaluation(evalCtx, evaluator); } catch (Exception e) { - return evaluateLegacy(evalCtx, evaluator); + return interpretiveEvaluation(evalCtx, evaluator); } } - return evaluateLegacy(evalCtx, evaluator); + return interpretiveEvaluation(evalCtx, evaluator); } private boolean isComposite() { @@ -106,7 +108,7 @@ private Object evaluateComposite(long index, Evaluator evaluator, ExecutionConte return null; } - private Object evaluateLegacy(ExecutionContext evalCtx, Evaluator evaluator) { + private Object interpretiveEvaluation(ExecutionContext evalCtx, Evaluator evaluator) { TypeHandler typeSystem = new TypeHandler(); for (int i = 0; i < conditions.size(); i++) { Object condResult = evaluator.evaluate(conditions.get(i), evalCtx); @@ -117,7 +119,7 @@ private Object evaluateLegacy(ExecutionContext evalCtx, Evaluator evaluator) { return executeStatementSequence(elseStatements, evaluator, evalCtx); } - private Expr tryBuildUnifiedExpression() { + private Expr buildUnifiedExpressionIncremental() { if (conditions.isEmpty() || branchStatements.isEmpty() || conditions.size() != branchStatements.size()) { return null; } @@ -125,10 +127,17 @@ private Expr tryBuildUnifiedExpression() { return null; } - List indicatorExpressions = new ArrayList(conditions.size()); - List branchExpressions = new ArrayList(conditions.size()); + Expr elseExpr = extractPureBranchExpression(elseStatements); + if (elseExpr == null || !isPureExpression(elseExpr)) { + return null; + } - for (int i = 0; i < conditions.size(); i++) { + Expr unified = simplifyExpr(cloneExpr(elseExpr)); + if (countNodesWithinBudget(unified, MAX_FAST_PATH_EXPR_NODES) > MAX_FAST_PATH_EXPR_NODES) { + return null; + } + + for (int i = conditions.size() - 1; i >= 0; i--) { Expr condition = conditions.get(i); if (condition == null || !isPureExpression(condition)) { return null; @@ -137,32 +146,90 @@ private Expr tryBuildUnifiedExpression() { if (indicator == null) { return null; } - indicatorExpressions.add(indicator); - Expr branchExpr = extractPureBranchExpression(branchStatements.get(i)); if (branchExpr == null || !isPureExpression(branchExpr)) { return null; } - branchExpressions.add(branchExpr); - } - Expr elseExpr = extractPureBranchExpression(elseStatements); - if (elseExpr == null || !isPureExpression(elseExpr)) { - return null; - } - - Expr unified = cloneExpr(elseExpr); - for (int i = indicatorExpressions.size() - 1; i >= 0; i--) { - Expr indicator = cloneExpr(indicatorExpressions.get(i)); - Expr branchExpr = cloneExpr(branchExpressions.get(i)); + indicator = simplifyExpr(cloneExpr(indicator)); + branchExpr = simplifyExpr(cloneExpr(branchExpr)); Expr complementIndicator = simplifyExpr(ASTFactory.createBinaryOp(one(), "-", indicator, null)); Expr leftTerm = simplifyExpr(ASTFactory.createBinaryOp(indicator, "*", branchExpr, null)); Expr rightTerm = simplifyExpr(ASTFactory.createBinaryOp(complementIndicator, "*", unified, null)); unified = simplifyExpr(ASTFactory.createBinaryOp(leftTerm, "+", rightTerm, null)); + if (countNodesWithinBudget(unified, MAX_FAST_PATH_EXPR_NODES) > MAX_FAST_PATH_EXPR_NODES) { + return null; + } } return simplifyExpr(unified); } + private int countNodesWithinBudget(Expr expr, int maxNodes) { + if (expr == null) return 0; + int count = 1; + if (count > maxNodes) return count; + + if (expr instanceof BinaryOp) { + BinaryOp op = (BinaryOp) expr; + count += countNodesWithinBudget(op.left, maxNodes - count); + if (count > maxNodes) return count; + count += countNodesWithinBudget(op.right, maxNodes - count); + return count; + } + if (expr instanceof Unary) { + Unary unary = (Unary) expr; + count += countNodesWithinBudget(unary.operand, maxNodes - count); + return count; + } + if (expr instanceof TypeCast) { + TypeCast cast = (TypeCast) expr; + count += countNodesWithinBudget(cast.expression, maxNodes - count); + return count; + } + if (expr instanceof ExprIf) { + ExprIf exprIf = (ExprIf) expr; + count += countNodesWithinBudget(exprIf.condition, maxNodes - count); + if (count > maxNodes) return count; + count += countNodesWithinBudget(exprIf.thenExpr, maxNodes - count); + if (count > maxNodes) return count; + count += countNodesWithinBudget(exprIf.elseExpr, maxNodes - count); + return count; + } + if (expr instanceof EqualityChain) { + EqualityChain chain = (EqualityChain) expr; + count += countNodesWithinBudget(chain.left, maxNodes - count); + if (count > maxNodes) return count; + if (chain.chainArguments != null) { + for (Expr arg : chain.chainArguments) { + count += countNodesWithinBudget(arg, maxNodes - count); + if (count > maxNodes) return count; + } + } + return count; + } + if (expr instanceof ChainedComparison) { + ChainedComparison chain = (ChainedComparison) expr; + if (chain.expressions != null) { + for (Expr item : chain.expressions) { + count += countNodesWithinBudget(item, maxNodes - count); + if (count > maxNodes) return count; + } + } + return count; + } + if (expr instanceof BooleanChain) { + BooleanChain chain = (BooleanChain) expr; + if (chain.expressions != null) { + for (Expr item : chain.expressions) { + count += countNodesWithinBudget(item, maxNodes - count); + if (count > maxNodes) return count; + } + } + return count; + } + return count; + } + private Expr extractPureBranchExpression(List statements) { if (statements == null) return null; Map tempExpressions = new HashMap(); From 04c2b10d45d857a1e08a3757a091d13af3c3c85c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:35:40 +0000 Subject: [PATCH 2/4] Refine pending update tree lookup pruning and cleanup fast-path node counter Agent-Logs-Url: https://github.com/DanexCodr/Coderive/sessions/e09efce3-65e4-4b52-b570-1f833e7bbc72 Co-authored-by: DanexCodr <216312766+DanexCodr@users.noreply.github.com> --- src/main/java/cod/range/NaturalArray.java | 51 ++++++++++++++++++- .../cod/range/formula/ConditionalFormula.java | 1 - 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/cod/range/NaturalArray.java b/src/main/java/cod/range/NaturalArray.java index 0ea3bd96..0eb8c5ed 100644 --- a/src/main/java/cod/range/NaturalArray.java +++ b/src/main/java/cod/range/NaturalArray.java @@ -70,6 +70,8 @@ public class NaturalArray { private static final int PENDING_UPDATES_TREE_THRESHOLD = 100; private List pendingUpdates = new ArrayList(); private NavigableMap> pendingUpdatesByStart = null; + private NavigableMap pendingUpdateOrderPrefixByStart = null; + private boolean pendingUpdateOrderPrefixDirty = false; private long nextPendingUpdateOrder = 0L; private boolean hasPendingUpdates = false; @@ -1168,6 +1170,7 @@ private void addPendingUpdateToTree(PendingRangeUpdate update) { pendingUpdatesByStart.put(update.range.start, updatesAtStart); } updatesAtStart.add(update); + pendingUpdateOrderPrefixDirty = true; } private void convertPendingUpdatesToTreeIndex() { @@ -1177,6 +1180,30 @@ private void convertPendingUpdatesToTreeIndex() { } } + private void rebuildPendingUpdateOrderPrefix() { + if (pendingUpdatesByStart == null) { + pendingUpdateOrderPrefixByStart = null; + pendingUpdateOrderPrefixDirty = false; + return; + } + + pendingUpdateOrderPrefixByStart = new TreeMap(); + long runningMax = Long.MIN_VALUE; + for (Map.Entry> entry : pendingUpdatesByStart.entrySet()) { + long bucketMax = Long.MIN_VALUE; + for (PendingRangeUpdate update : entry.getValue()) { + if (update.order > bucketMax) { + bucketMax = update.order; + } + } + if (bucketMax > runningMax) { + runningMax = bucketMax; + } + pendingUpdateOrderPrefixByStart.put(entry.getKey(), runningMax); + } + pendingUpdateOrderPrefixDirty = false; + } + private PendingRangeUpdate resolvePendingUpdateForIndex(long index) { if (pendingUpdatesByStart == null) { for (int i = pendingUpdates.size() - 1; i >= 0; i--) { @@ -1188,10 +1215,19 @@ private PendingRangeUpdate resolvePendingUpdateForIndex(long index) { return null; } + if (pendingUpdateOrderPrefixDirty || pendingUpdateOrderPrefixByStart == null) { + rebuildPendingUpdateOrderPrefix(); + } + PendingRangeUpdate winner = null; NavigableMap> candidatesByStart = pendingUpdatesByStart.headMap(index, true); - for (List updatesAtStart : candidatesByStart.values()) { - for (PendingRangeUpdate candidate : updatesAtStart) { + for (Map.Entry> entry : candidatesByStart.descendingMap().entrySet()) { + List updatesAtStart = entry.getValue(); + for (int i = updatesAtStart.size() - 1; i >= 0; i--) { + PendingRangeUpdate candidate = updatesAtStart.get(i); + if (winner != null && candidate.order <= winner.order) { + break; + } if (!candidate.contains(index)) { continue; } @@ -1199,6 +1235,13 @@ private PendingRangeUpdate resolvePendingUpdateForIndex(long index) { winner = candidate; } } + + if (winner != null && pendingUpdateOrderPrefixByStart != null) { + Long remainingMaxOrder = pendingUpdateOrderPrefixByStart.get(entry.getKey()); + if (remainingMaxOrder != null && winner.order >= remainingMaxOrder.longValue()) { + break; + } + } } return winner; } @@ -1245,6 +1288,8 @@ public int compare(PendingRangeUpdate a, PendingRangeUpdate b) { pendingUpdates.clear(); pendingUpdatesByStart = null; + pendingUpdateOrderPrefixByStart = null; + pendingUpdateOrderPrefixDirty = false; hasPendingUpdates = false; } @@ -1754,6 +1799,8 @@ public int getPendingUpdateCount() { public void discardUpdates() { pendingUpdates.clear(); pendingUpdatesByStart = null; + pendingUpdateOrderPrefixByStart = null; + pendingUpdateOrderPrefixDirty = false; hasPendingUpdates = false; } diff --git a/src/main/java/cod/range/formula/ConditionalFormula.java b/src/main/java/cod/range/formula/ConditionalFormula.java index 0931857b..e2d3c44d 100644 --- a/src/main/java/cod/range/formula/ConditionalFormula.java +++ b/src/main/java/cod/range/formula/ConditionalFormula.java @@ -167,7 +167,6 @@ private Expr buildUnifiedExpressionIncremental() { private int countNodesWithinBudget(Expr expr, int maxNodes) { if (expr == null) return 0; int count = 1; - if (count > maxNodes) return count; if (expr instanceof BinaryOp) { BinaryOp op = (BinaryOp) expr; From cbb5c5298765d3864aac7e2c7471c1c4de121d94 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:37:09 +0000 Subject: [PATCH 3/4] Minor cleanup in pending update tree comparison Agent-Logs-Url: https://github.com/DanexCodr/Coderive/sessions/e09efce3-65e4-4b52-b570-1f833e7bbc72 Co-authored-by: DanexCodr <216312766+DanexCodr@users.noreply.github.com> --- src/main/java/cod/range/NaturalArray.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cod/range/NaturalArray.java b/src/main/java/cod/range/NaturalArray.java index 0eb8c5ed..ae276bd2 100644 --- a/src/main/java/cod/range/NaturalArray.java +++ b/src/main/java/cod/range/NaturalArray.java @@ -1238,7 +1238,7 @@ private PendingRangeUpdate resolvePendingUpdateForIndex(long index) { if (winner != null && pendingUpdateOrderPrefixByStart != null) { Long remainingMaxOrder = pendingUpdateOrderPrefixByStart.get(entry.getKey()); - if (remainingMaxOrder != null && winner.order >= remainingMaxOrder.longValue()) { + if (remainingMaxOrder != null && winner.order >= remainingMaxOrder) { break; } } From 589bd760bcb8738613e6199861da0393c4c3cb7a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:24:36 +0000 Subject: [PATCH 4/4] Implement matrix-power-to-vector recurrence optimization and expand recurrence stress tests Agent-Logs-Url: https://github.com/DanexCodr/Coderive/sessions/666ae70e-6c69-416c-adf2-c1a2f0a942da Co-authored-by: DanexCodr <216312766+DanexCodr@users.noreply.github.com> --- .../LinearRecurrenceOptimization.cod | 15 +++++++++ .../VectorLinearRecurrenceOptimization.cod | 12 +++++++ .../formula/LinearRecurrenceFormula.java | 24 +++++--------- .../formula/VectorRecurrenceFormula.java | 31 ++++++++----------- 4 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/LinearRecurrenceOptimization.cod b/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/LinearRecurrenceOptimization.cod index 8972eacc..be1044b2 100644 --- a/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/LinearRecurrenceOptimization.cod +++ b/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/LinearRecurrenceOptimization.cod @@ -14,6 +14,12 @@ share main() { out("fib[10]=" + fib[10] + " expected=55") out("fib[20]=" + fib[20] + " expected=6765") out("fib[30]=" + fib[30] + " expected=832040") + out("fib[100]=" + fib[100] + " expected=354224848179261915075") + out("fib[500]=" + fib[500]) + out("fib[1000]=" + fib[1000]) + out("fib[1500]=" + fib[1500]) + out("fib[1999]=" + fib[1999]) + out("fib[2000]=" + fib[2000]) jac := [0 to 2000] jac[0] = 0 @@ -33,5 +39,14 @@ share main() { out("shift[2]=" + shift[2] + " expected=6") out("shift[3]=" + shift[3] + " expected=12") out("shift[10]=" + shift[10] + " expected=495") + + ramp := [0 to 2000] + ramp[0] = 1 + for i of [1 to 2000] { + ramp[i] = ramp[i-1] + 7 + } + out("ramp[10]=" + ramp[10] + " expected=71") + out("ramp[1000]=" + ramp[1000] + " expected=7001") + out("ramp[2000]=" + ramp[2000] + " expected=14001") out("elapsed_ms=" + (timer() - start)) } diff --git a/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/VectorLinearRecurrenceOptimization.cod b/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/VectorLinearRecurrenceOptimization.cod index a9d5cec8..dea01d39 100644 --- a/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/VectorLinearRecurrenceOptimization.cod +++ b/src/main/cod/demo/src/main/test/linearrecurrenceoptimization/VectorLinearRecurrenceOptimization.cod @@ -21,6 +21,12 @@ share main() { out("pair1-b[10]=" + b[10] + " expected=16") out("pair1-a[20]=" + a[20] + " expected=1536") out("pair1-b[20]=" + b[20] + " expected=512") + out("pair1-a[100]=" + a[100]) + out("pair1-b[100]=" + b[100]) + out("pair1-a[150]=" + a[150]) + out("pair1-b[150]=" + b[150]) + out("pair1-a[200]=" + a[200]) + out("pair1-b[200]=" + b[200]) c := [0 to 200] d := [0 to 200] @@ -39,5 +45,11 @@ share main() { out("pair2-d[10]=" + d[10] + " expected=41") out("pair2-c[20]=" + c[20] + " expected=3070") out("pair2-d[20]=" + d[20] + " expected=1367") + out("pair2-c[100]=" + c[100]) + out("pair2-d[100]=" + d[100]) + out("pair2-c[150]=" + c[150]) + out("pair2-d[150]=" + d[150]) + out("pair2-c[200]=" + c[200]) + out("pair2-d[200]=" + d[200]) out("elapsed_ms=" + (timer() - start)) } diff --git a/src/main/java/cod/range/formula/LinearRecurrenceFormula.java b/src/main/java/cod/range/formula/LinearRecurrenceFormula.java index bfe21854..6fbace6e 100644 --- a/src/main/java/cod/range/formula/LinearRecurrenceFormula.java +++ b/src/main/java/cod/range/formula/LinearRecurrenceFormula.java @@ -117,8 +117,7 @@ public Object evaluate(long index) { AutoStackingNumber[][] transition = buildTransition(dim); AutoStackingNumber[] state = buildBaseState(dim); - AutoStackingNumber[][] power = matrixPow(transition, steps); - AutoStackingNumber[] result = multiply(power, state); + AutoStackingNumber[] result = applyMatrixPowerToVector(transition, steps, state); synchronized (this) { rollingState = copyState(result); rollingIndex = index; @@ -195,14 +194,17 @@ private void resetRollingState() { rollingState = null; } - private AutoStackingNumber[][] matrixPow(AutoStackingNumber[][] base, long exp) { - int dim = base.length; - AutoStackingNumber[][] result = identity(dim); + private AutoStackingNumber[] applyMatrixPowerToVector(AutoStackingNumber[][] base, long exp, AutoStackingNumber[] vector) { + AutoStackingNumber[] result = Arrays.copyOf(vector, vector.length); + if (exp <= 0) { + return result; + } + AutoStackingNumber[][] current = base; long e = exp; while (e > 0) { if ((e & 1L) == 1L) { - result = multiply(result, current); + result = multiply(current, result); } e >>= 1; if (e > 0) { @@ -212,16 +214,6 @@ private AutoStackingNumber[][] matrixPow(AutoStackingNumber[][] base, long exp) return result; } - private AutoStackingNumber[][] identity(int dim) { - AutoStackingNumber[][] id = new AutoStackingNumber[dim][dim]; - for (int i = 0; i < dim; i++) { - for (int j = 0; j < dim; j++) { - id[i][j] = (i == j) ? ONE : ZERO; - } - } - return id; - } - private AutoStackingNumber[][] multiply(AutoStackingNumber[][] a, AutoStackingNumber[][] b) { int n = a.length; AutoStackingNumber[][] out = new AutoStackingNumber[n][n]; diff --git a/src/main/java/cod/range/formula/VectorRecurrenceFormula.java b/src/main/java/cod/range/formula/VectorRecurrenceFormula.java index b91d9c25..4f65fac6 100644 --- a/src/main/java/cod/range/formula/VectorRecurrenceFormula.java +++ b/src/main/java/cod/range/formula/VectorRecurrenceFormula.java @@ -92,8 +92,10 @@ public synchronized Object evaluate(long index, int sequenceIndex) { AutoStackingNumber[][] transition = buildTransition(baseDim, matrixDim); AutoStackingNumber[] state = buildBaseState(baseDim, matrixDim); - AutoStackingNumber[][] power = matrixPow(transition, steps); - AutoStackingNumber[] result = multiply(power, state); + if (state == null) { + return null; + } + AutoStackingNumber[] result = applyMatrixPowerToVector(transition, steps, state); rollingState = Arrays.copyOf(result, baseDim); rollingIndex = index; @@ -184,33 +186,26 @@ private void advanceRollingState() { rollingState = nextState; } - private AutoStackingNumber[][] matrixPow(AutoStackingNumber[][] base, long exp) { - int dim = base.length; - AutoStackingNumber[][] result = identity(dim); + private AutoStackingNumber[] applyMatrixPowerToVector(AutoStackingNumber[][] base, long exp, AutoStackingNumber[] vector) { + AutoStackingNumber[] result = Arrays.copyOf(vector, vector.length); + if (exp <= 0L) { + return result; + } + AutoStackingNumber[][] current = base; long e = exp; - while (e > 0) { + while (e > 0L) { if ((e & 1L) == 1L) { - result = multiply(result, current); + result = multiply(current, result); } e >>= 1; - if (e > 0) { + if (e > 0L) { current = multiply(current, current); } } return result; } - private AutoStackingNumber[][] identity(int dim) { - AutoStackingNumber[][] id = new AutoStackingNumber[dim][dim]; - for (int i = 0; i < dim; i++) { - for (int j = 0; j < dim; j++) { - id[i][j] = (i == j) ? ONE : ZERO; - } - } - return id; - } - private AutoStackingNumber[][] multiply(AutoStackingNumber[][] a, AutoStackingNumber[][] b) { int n = a.length; AutoStackingNumber[][] out = new AutoStackingNumber[n][n];