**Build scan:**
https://gradle-enterprise.elastic.co/s/jjsb3opg5n7iy/tests/:x-pack:plugin:ml:test/org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlannerTests/testTooManyNodesAndModels_DoesNotThrowOOM_GivenNodesJustUnderLimit

**Reproduction line:**
`./gradlew ':x-pack:plugin:ml:test' --tests "org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlannerTests.testTooManyNodesAndModels_DoesNotThrowOOM_GivenNodesJustUnderLimit" -Dtests.seed=110A9DC5977D6165 -Dbuild.snapshot=false -Dtests.jvm.argline="-Dbuild.snapshot=false" -Dtests.locale=es-MX -Dtests.timezone=GB -Druntime.java=17`

**Applicable branches:**
master

**Reproduces locally?:**
Yes

**Failure history:**
https://gradle-enterprise.elastic.co/scans/tests?tests.container=org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlannerTests&tests.test=testTooManyNodesAndModels_DoesNotThrowOOM_GivenNodesJustUnderLimit

**Failure excerpt:**
```
java.lang.OutOfMemoryError: Java heap space

  at __randomizedtesting.SeedInfo.seed([110A9DC5977D6165:1B9089CC55E53785]:0)
  at org.ojalgo.array.Primitive64Array.<init>(Primitive64Array.java:112)
  at org.ojalgo.matrix.store.Primitive64Store.<init>(Primitive64Store.java:413)
  at org.ojalgo.matrix.store.Primitive64Store$1.make(Primitive64Store.java:173)
  at org.ojalgo.matrix.store.Primitive64Store$1.make(Primitive64Store.java:70)
  at org.ojalgo.structure.Factory2D.make(Factory2D.java:115)
  at org.ojalgo.optimisation.linear.SimplexTableau$DenseTableau.<init>(SimplexTableau.java:61)
  at org.ojalgo.optimisation.linear.SimplexTableau.make(SimplexTableau.java:764)
  at org.ojalgo.optimisation.linear.PrimalSimplex.build(PrimalSimplex.java:128)
  at org.ojalgo.optimisation.linear.LinearSolver$ModelIntegration.build(LinearSolver.java:183)
  at org.ojalgo.optimisation.linear.LinearSolver$ModelIntegration.build(LinearSolver.java:172)
  at org.ojalgo.optimisation.ExpressionsBasedModel$Intermediate.getSolver(ExpressionsBasedModel.java:335)
  at org.ojalgo.optimisation.ExpressionsBasedModel$Intermediate.solve(ExpressionsBasedModel.java:276)
  at org.ojalgo.optimisation.ExpressionsBasedModel.optimise(ExpressionsBasedModel.java:1665)
  at org.ojalgo.optimisation.ExpressionsBasedModel.maximise(ExpressionsBasedModel.java:1193)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.LinearProgrammingPlanSolver.solveLinearProgram(LinearProgrammingPlanSolver.java:292)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.LinearProgrammingPlanSolver.solvePlan(LinearProgrammingPlanSolver.java:93)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlanner.solvePreservingPreviousAssignments(AssignmentPlanner.java:71)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlanner.solveKeepingOneAllocationOnPreviousAssignments(AssignmentPlanner.java:61)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlanner.computePlan(AssignmentPlanner.java:49)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlannerTests.runTooManyNodesAndModels(AssignmentPlannerTests.java:412)
  at org.elasticsearch.xpack.ml.inference.assignment.planning.AssignmentPlannerTests.testTooManyNodesAndModels_DoesNotThrowOOM_GivenNodesJustUnderLimit(AssignmentPlannerTests.java:250)
  at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
  at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
  at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:568)
  at com.carrotsearch.randomizedtesting.RandomizedRunner.invoke(RandomizedRunner.java:1758)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$8.evaluate(RandomizedRunner.java:946)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$9.evaluate(RandomizedRunner.java:982)
  at com.carrotsearch.randomizedtesting.RandomizedRunner$10.evaluate(RandomizedRunner.java:996)
  at com.carrotsearch.randomizedtesting.rules.StatementAdapter.evaluate(StatementAdapter.java:36)
  at org.apache.lucene.tests.util.TestRuleSetupTeardownChained$1.evaluate(TestRuleSetupTeardownChained.java:44)
  at org.apache.lucene.tests.util.AbstractBeforeAfterRule$1.evaluate(AbstractBeforeAfterRule.java:43)

```
x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/inference/assignment/planning/AssignmentPlannerTests.java
}
            if (quality.allocationRate > 0) {
                allocationPercent.add(quality.allocationRate);
            }
            times.add(stopWatch.totalTime().millis());
        }
        double avgCoreUtilization = coreUtilization.stream().mapToDouble(Double::doubleValue).average().getAsDouble();
        logger.debug("BC time = " + times.stream().mapToLong(Long::longValue).min().getAsLong() + " ms");
        logger.debug("WC time = " + times.stream().mapToLong(Long::longValue).max().getAsLong() + " ms");
        logger.debug("Avg time = " + times.stream().mapToLong(Long::longValue).average().getAsDouble() + " ms");
        logger.debug("Avg nodes = " + nodeSizes.stream().mapToLong(Integer::intValue).average().getAsDouble());
        logger.debug("Avg models = " + modelSizes.stream().mapToLong(Integer::intValue).average().getAsDouble());
        logger.debug("Avg core utilization = " + avgCoreUtilization);
        logger.debug("WC core utilization = " + coreUtilization.stream().mapToDouble(Double::doubleValue).min().getAsDouble());
        logger.debug("Avg allocation % = " + allocationPercent.stream().mapToDouble(Double::doubleValue).average().getAsDouble());
        logger.debug("WC allocation % = " + allocationPercent.stream().mapToDouble(Double::doubleValue).min().getAsDouble());
        assertThat(avgCoreUtilization, greaterThanOrEqualTo(0.95));
    }
    public void testPreviousAssignmentsGetAtLeastAsManyAllocationsAfterAddingNewModel() {
        int scale = randomIntBetween(0, 10);
        double load = randomDoubleBetween(0.1, 1.0, true);
        List<Node> nodes = randomNodes(scale);
        List<Model> models = randomModels(scale, load, nodes);
        AssignmentPlan originalPlan = new AssignmentPlanner(nodes, models).computePlan();
        List<Model> previousModelsPlusNew = new ArrayList<>(models.size() + 1);
        for (Model m : models) {
            Map<Node, Integer> assignments = originalPlan.assignments(m).orElse(Map.of());
            Map<String, Integer> previousAssignments = assignments.entrySet()
                .stream()
                .collect(Collectors.toMap(e -> e.getKey().id(), Map.Entry::getValue));