Files
cut-abstractions/tests/dev1/dataHandle/common/core/OptimizeMachine.ts
2025-07-22 18:22:31 +08:00

164 lines
4.5 KiB
TypeScript

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<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, 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() {
}
}