import { arrayRemoveIf } from '../ArrayExt' import { clipperCpp } from '../ClipperCpp' import { Sleep } from '../Sleep' import { Individual } from './Individual' import { NestCache } from './NestCache' import { DefaultComparePointKeys } from './NestDatabase' import type { Part } from './Part' import type { Path } from './Path' /** * 优化器 * 配置优化器 * 放入零件 * 按下启动 * 按下暂停 * 清理机台 */ export class OptimizeMachine { // 配置 Config: { PopulationCount: number// 种群个数 } Bin: Path // 默认的容器 OddmentsBins: Path[]// 余料容器列表 Parts: Part[] // 所有的零件 ComparePointKeys: string[] = DefaultComparePointKeys// 用来决定零件靠边模式 // //计算重复的零件 TODO:需要对相同的零件提取出来 // PartCount: number[] = []; 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 // //计算重复的零件(暂时不用) // for (let part of parts) // { // let count = this.PartCount[part.Id]; // this.PartCount[part.Id] = count === undefined ? 1 : (count + 1); // } } callBack: (i: Individual) => Promise // 启动 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, this.Bin, this.OddmentsBins, this.ComparePointKeys)] for (let i = 1; i < this.Config.PopulationCount; i++) { const 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, this.Bin, this.OddmentsBins, this.ComparePointKeys)) } // 2.执行 await this.Run() } calcCount = 0 best = Number.POSITIVE_INFINITY bestP: Individual bestCount = 0 private async Run() { console.time('1') if (this.Parts.length === 0) return // 开始自然选择 while (!this._IsSuspend) // 实验停止信号 { const goBack = this.calcCount - this.bestCount > 8000 // 1.适应环境(放置零件) for (let i = 0; i < this._Individuals.length; i++) { if (globalThis.document || !clipperCpp.lib) await Sleep(0) const p = this._Individuals[i] if (this.calcCount < 1000 || this.calcCount % 1000 === 0) p.Evaluate(this.best, true, i % 3) else p.Evaluate(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) { await Sleep(0) } this._Individuals.sort((i1, i2) => i1.Fitness - i2.Fitness) const 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 (const 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() { } }