refactor: rename Astra engine to Gpt6Astra

OpenAI reuses model codenames across generations (GPT-6 reused
GPT-5.6's Sol and Luna), so a bare codename like "Astra" can't
identify which model built the engine. Prefixing the model version
keeps engine names unambiguous as more runs are added. The CLR type
is now Gpt6AstraNestingEngine, so benchmark reports show the new name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
aj
2026-09-24 10:36:00 -04:00
co-authored by Claude Opus 5.5
parent 70ae0cc155
commit 755ea4d7f8
28 changed files with 63 additions and 63 deletions
@@ -0,0 +1,94 @@
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.Loader;
using OpenNest;
using OpenNest.CNC;
using OpenNest.Engine.Jobs;
using OpenNest.Engine.Jobs.Adapters;
using OpenNest.Geometry;
using OpenNest.Benchmark;
using CncProgram = OpenNest.CNC.Program;
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
if (args.Contains("--diagnose-ring"))
{
var ringPart = new NestJobPart("ring", PartGeometrySnapshot.FromProgram(
new OpenNest.Shapes.RingShape { OuterDiameter = 10, InnerDiameter = 7 }.GetDrawing().Program), 1);
var insertPart = new NestJobPart("insert", PartGeometrySnapshot.FromProgram(
new OpenNest.Shapes.CircleShape { Diameter = 6 }.GetDrawing().Program), 1);
foreach (var quadrant in new[] { 1, 2 })
foreach (var offset in new[] { 0.0, 0.0003, 0.05, 0.1 })
{
var s = new NestPlateStock("s", new Size(24, 42), 1, 0.175,
new Spacing(0.2, 0.3, 0.4, 0.5), quadrant);
var j = new NestJob(new[] { ringPart, insertPart }, new[] { s });
var x = (quadrant == 1 ? 0 : -42) + s.EdgeSpacing.Left + 5;
var y = s.EdgeSpacing.Bottom + 5;
var result = new NestJobResult(NestJobStatus.Complete, NestJobStopReason.Completed,
new[] { new NestJobPlateResult(0, s, new[] { new NestJobPlacement("ring", 0, x, y, 0),
new NestJobPlacement("insert", 0, x + offset, y, 0) }) },
new[] { new PartFulfillment("ring", 1, 1, 0), new PartFulfillment("insert", 1, 1, 0) },
new[] { new StockUsage("s", 1, 0) });
var materialized = NestResultMaterializer.Materialize(j, result);
var check = NestValidator.Validate(materialized.Nest.Plates.Select(p => (p, p.Parts.ToList())).ToList(),
j.Parts.ToDictionary(p => materialized.DrawingsByPartId[p.Id], p => (p.Id, p.Quantity)));
Console.WriteLine($"q={quadrant} offset={offset} valid={check.Valid}: {string.Join(';', check.Violations)}");
}
return;
}
var assembly = args.Length > 0 && args[0].EndsWith(".dll")
? new AssemblyLoadContext("benchmark-plugin", isCollectible: true).LoadFromAssemblyPath(Path.GetFullPath(args[0])) : Assembly.Load("OpenNest.Engine.Gpt6Astra");
var engine = (INestingEngine)Activator.CreateInstance(assembly.GetType("OpenNest.Engine.Gpt6Astra.Gpt6AstraNestingEngine")!);
var cases = new List<(string Name, NestJob Job)>();
var standard = new[] { new NestPlateStock("small", new Size(24, 48), partSpacing: 0.15),
new NestPlateStock("large", new Size(48, 96), partSpacing: 0.15) };
NestJobPart Part(string name, CncProgram p, int count, RotationPolicy rotation = null) =>
new(name, PartGeometrySnapshot.FromProgram(p), count, rotation: rotation);
CncProgram Polygon(params double[] xy)
{
var p = new CncProgram(); p.MoveTo(xy[0], xy[1]);
for (var i = 2; i < xy.Length; i += 2) p.LineTo(xy[i], xy[i + 1]);
p.LineTo(xy[0], xy[1]); return p;
}
CncProgram Rect(double w, double h) => Polygon(0, 0, w, 0, w, h, 0, h);
CncProgram Circle(double r) { var p = new CncProgram(); p.MoveTo(r, 0); p.ArcTo(r, 0, 0, 0, RotationType.CCW); return p; }
void Add(string name, NestJobPart[] parts, NestPlateStock[] stocks = null, NestJobOptions options = null) =>
cases.Add((name, new NestJob(parts, stocks ?? standard, options)));
Add("triangles", new[] { Part("triangle", Polygon(0, 0, 10, 0, 0, 10), 60) });
Add("circles", new[] { Part("circle", Circle(2.5), 90) });
Add("circles-dense", new[] { Part("circle", Circle(2.5), 80) });
Add("concave-L", new[] { Part("L", Polygon(0, 0, 8, 0, 8, 2, 2, 2, 2, 8, 0, 8), 60) });
Add("mixed", new[] { Part("rect", Rect(9, 4), 30), Part("triangle", Polygon(0, 0, 8, 0, 3, 6), 25),
Part("circle", Circle(2), 30), Part("L", Polygon(0, 0, 7, 0, 7, 2, 2, 2, 2, 6, 0, 6), 20) });
var ring = Rect(10, 10); ring.MoveTo(1, 1); ring.LineTo(1, 9); ring.LineTo(9, 9); ring.LineTo(9, 1); ring.LineTo(1, 1);
Add("holes", new[] { Part("frame", ring, 8), Part("insert", Rect(7, 7), 8) });
Add("rectangles", Enumerable.Range(0, 8).Select(i => Part($"r{i}", Rect(2 + i, 3 + i % 3), 12)).ToArray());
Add("grain", new[] { Part("fixed", Rect(13, 3), 20, RotationPolicy.Fixed(System.Math.PI / 6)),
Part("sweep", Rect(7, 2), 40, RotationPolicy.BoundedSweep(0, System.Math.PI / 2, System.Math.PI / 4)) });
Add("scarce-stock", new[] { Part("small", Rect(4, 4), 8), Part("large", Rect(10, 10), 1) },
new[] { new NestPlateStock("scarce", new Size(10, 10), 1), new NestPlateStock("small-only", new Size(4, 8)) });
Add("tail", new[] { Part("rect", Rect(6, 4), 17) }, new[] {
new NestPlateStock("small", new Size(8, 12), partSpacing: 0.1), new NestPlateStock("large", new Size(20, 30), partSpacing: 0.1) });
Add("plate-cap", new[] { Part("r", Rect(5, 5), 10) }, new[] {
new NestPlateStock("small", new Size(10, 10)), new NestPlateStock("large", new Size(20, 20)) }, new NestJobOptions(maxPlates: 1));
cases.AddRange(OpenNest.Engine.Gpt6Astra.Benchmarks.GeneratedCases.Create());
Console.WriteLine("case,valid,placed,requested,sheets,area,milliseconds");
foreach (var (name, job) in cases)
{
if (args.Length > 1 && !name.Contains(args[1], StringComparison.OrdinalIgnoreCase)) continue;
var sw = Stopwatch.StartNew();
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(90));
try
{
var result = engine.Solve(job, token: cts.Token); sw.Stop();
var nest = NestResultMaterializer.Materialize(job, result);
var validation = NestValidator.Validate(nest.Nest.Plates.Select(p => (p, p.Parts.ToList())).ToList(),
job.Parts.ToDictionary(p => nest.DrawingsByPartId[p.Id], p => (p.Id, p.Quantity)));
NestValidator.ValidateAgainstJob(job, result, job.Parts.ToDictionary(p => p.Id, p => p.Id), validation);
if (!validation.Valid) Environment.ExitCode = 1;
Console.WriteLine($"{name},{validation.Valid},{result.Fulfillment.Sum(f => f.Placed)},{job.Parts.Sum(p => p.Quantity)},{result.Plates.Count},{result.Plates.Sum(p => p.Stock.Size.Length * p.Stock.Size.Width)},{sw.ElapsedMilliseconds}");
foreach (var violation in validation.Violations.Take(4)) Console.Error.WriteLine($"{name}: {violation}");
}
catch (Exception ex) { Environment.ExitCode = 1; Console.WriteLine($"{name},ERROR,,,,,{sw.ElapsedMilliseconds}"); Console.Error.WriteLine(ex); }
}