161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
![]() |
import { arrayRemoveIf } from "../../Common/ArrayExt";
|
||
|
import { Sleep } from "../../Common/Sleep";
|
||
|
import { clipperCpp } from "../Common/ClipperCpp";
|
||
|
import { Individual } from "./Individual";
|
||
|
import { NestCache } from "./NestCache";
|
||
|
import { Part } from "./Part";
|
||
|
import { Path } from "./Path";
|
||
|
|
||
|
/**
|
||
|
* 优化器
|
||
|
* 配置优化器
|
||
|
* 放入零件
|
||
|
* 按下启动
|
||
|
* 按下暂停
|
||
|
* 清理机台
|
||
|
*/
|
||
|
export class OptimizeMachine
|
||
|
{
|
||
|
//配置
|
||
|
Config: {
|
||
|
PopulationCount: number;//种群个数
|
||
|
};
|
||
|
//容器板
|
||
|
Bin: Path;
|
||
|
//机台上的零件
|
||
|
Parts: Part[];
|
||
|
private _IsSuspend = false;
|
||
|
|
||
|
protected _Individuals: Individual[];
|
||
|
|
||
|
constructor()
|
||
|
{
|
||
|
this.Config = { PopulationCount: 50 };
|
||
|
}
|
||
|
|
||
|
//放入零件
|
||
|
PutParts(parts: Part[])
|
||
|
{
|
||
|
if (globalThis.document) parts = parts.slice();
|
||
|
arrayRemoveIf(parts, p => p.RotatedStates.length === 0);
|
||
|
this.Parts = parts;
|
||
|
}
|
||
|
|
||
|
callBack: (i: Individual) => Promise<void>;
|
||
|
|
||
|
//启动
|
||
|
async Start()
|
||
|
{
|
||
|
if (this.Parts.length === 0) return;
|
||
|
console.log(this.Parts.length);
|
||
|
this._IsSuspend = false;
|
||
|
NestCache.Clear();
|
||
|
this.Parts.sort((p1, p2) => p2.State.Contour.Area - p1.State.Contour.Area);
|
||
|
this._Individuals = [new Individual(this.Parts, 0.8)];
|
||
|
for (let i = 1; i < this.Config.PopulationCount; i++)
|
||
|
{
|
||
|
let parts = this.Parts.map(p => p.Clone());
|
||
|
if (i < 3)
|
||
|
{
|
||
|
for (let i = parts.length - 1; i > 0; i--)
|
||
|
{
|
||
|
const j = Math.floor(Math.random() * (i + 1));
|
||
|
[parts[i], parts[j]] = [parts[j], parts[i]];
|
||
|
parts[i].Mutate();
|
||
|
}
|
||
|
}
|
||
|
this._Individuals.push(new Individual(parts, 0.8));
|
||
|
}
|
||
|
//2.执行
|
||
|
await this.Run();
|
||
|
}
|
||
|
|
||
|
calcCount = 0;
|
||
|
best = Infinity;
|
||
|
bestP: Individual;
|
||
|
bestCount = 0;
|
||
|
private async Run()
|
||
|
{
|
||
|
console.time("1");
|
||
|
if (this.Parts.length === 0) return;
|
||
|
//开始自然选择
|
||
|
while (!this._IsSuspend) //实验停止信号
|
||
|
{
|
||
|
let goBack = this.calcCount - this.bestCount > 8000;
|
||
|
//1.适应环境(放置零件)
|
||
|
for (let i = 0; i < this._Individuals.length; i++)
|
||
|
{
|
||
|
if (globalThis.document || !clipperCpp.lib)
|
||
|
await Sleep(0);
|
||
|
let p = this._Individuals[i];
|
||
|
if (this.calcCount < 1000 || this.calcCount % 1000 === 0)
|
||
|
p.Evaluate(this.Bin, this.best, true, i % 2);
|
||
|
else
|
||
|
p.Evaluate(this.Bin, this.best);
|
||
|
|
||
|
if (!this.bestP || p.Fitness < this.bestP.Fitness)
|
||
|
{
|
||
|
this.bestP = p;
|
||
|
this.best = p.Fitness;
|
||
|
await this.callBack(p);
|
||
|
}
|
||
|
if (goBack)
|
||
|
p.mutationRate = 0.5;
|
||
|
}
|
||
|
|
||
|
this.calcCount += this._Individuals.length;
|
||
|
if (this.calcCount % 100 === 0)
|
||
|
{
|
||
|
console.timeLog("1", this.bestP.Fitness, this.calcCount, NestCache.count1, NestCache.count2);
|
||
|
await Sleep(0);
|
||
|
}
|
||
|
|
||
|
this._Individuals.sort((i1, i2) => i1.Fitness - i2.Fitness);
|
||
|
let bestP = this._Individuals[0];
|
||
|
// //回调最好的
|
||
|
// if (bestP.Fitness < this.best)
|
||
|
// {
|
||
|
// this.best = bestP.Fitness;
|
||
|
// this.bestP = bestP;
|
||
|
// // console.timeLog("1", this.best, this.calcCount, NestCache.count1, NestCache.count2);
|
||
|
// if (this.callBack)
|
||
|
// await this.callBack(bestP);
|
||
|
// }
|
||
|
|
||
|
//自然选择
|
||
|
this._Individuals.splice(-10);//杀死它
|
||
|
for (let i = 0; i < 4; i++)
|
||
|
this._Individuals.push(bestP.Clone());
|
||
|
this._Individuals.push(this.bestP.Clone());
|
||
|
for (let i = 0; i < 3; i++)
|
||
|
this._Individuals.push(this._Individuals[1].Clone());
|
||
|
for (let i = 0; i < 2; i++)
|
||
|
this._Individuals.push(this._Individuals[2].Clone());
|
||
|
//全部突变
|
||
|
for (let p of this._Individuals)
|
||
|
{
|
||
|
if (p.Fitness !== undefined)
|
||
|
p.Mutate();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//暂停
|
||
|
Suspend()
|
||
|
{
|
||
|
console.timeEnd("1");
|
||
|
console.log(this.best, this.calcCount, NestCache.count1);
|
||
|
this._IsSuspend = true;
|
||
|
console.log("暂停");
|
||
|
}
|
||
|
//继续
|
||
|
Continue()
|
||
|
{
|
||
|
this._IsSuspend = false;
|
||
|
this.Run();
|
||
|
}
|
||
|
//清理机台
|
||
|
Clear()
|
||
|
{
|
||
|
}
|
||
|
}
|