定制基因型用于嵌套的芯片

发布于 2025-01-26 07:38:56 字数 3549 浏览 3 评论 0原文

我正在使用Jenetics使用nofitpolygon嵌套多边形列表,

我的函数可以通过列表中的顺序来获得多边形列表。

我调整了Travellingsman问题,以具有代表多边形列表的基因型,并在进化过程中变化。

现在,我想将旋转添加到基因型中,以获得更好的结果,但我不知道如何将其添加到我的代码中。

当前,嵌套的顺序决定了适合度,我想做的是,对于每个巢道,将双重值(DoubleChromosomose?)添加到代表巢穴旋转的基因型。

NestPath是代表多边形

    public class NFP_Nesting implements Problem<ISeq<NestPath>, EnumGene<NestPath>, Double>{

static Phenotype<EnumGene<NestPath>,Double> tmpBest = null;
static Result tmpBestResult =null;

private NestPath _binPolygon;
Map<String,List<NestPath>> nfpCache=new HashMap<>();

private final ISeq<NestPath> _list;

public NFP_Nesting(ISeq<NestPath> lista,NestPath binpolygon ,double binw, double binh) 
{
    _binPolygon = binpolygon;
    _list=Objects.requireNonNull(lista);

}

@Override
public Codec<ISeq<NestPath>, EnumGene<NestPath>> codec() {
    return Codecs.ofPermutation(_list);
}

@Override
public Function<ISeq<NestPath>, Double> fitness() {

    return this::scalar_fitness;

}


/**
 * @param seq_nestpath
 * @return Fitness of the model
 */
Double scalar_fitness(final ISeq<NestPath> seq_nestpath) {

    List<NestPath> paths = seq_nestpath.asList();

    final Random random = RandomRegistry.random();
    
    //TODO NOT RANDOM ROTATION
    List<Integer> ids = new ArrayList<>();  
    for(int i = 0 ; i < paths.size(); i ++){
        ids.add(paths.get(i).getId());
        NestPath n = paths.get(i);
        if(n.getPossibleRotations()!= null)
        {
            n.setRotation(n.getPossibleRotations()[random.nextInt(n.getPossibleRotations().length)]);
        }
    }

///复杂函数的类

    return fitness;

}



private static NFP_Nesting of (List<NestPath> l, NestPath binpol, double binw, double binh)
{
    final MSeq<NestPath> paths = MSeq.ofLength(l.size());

    final Random random = RandomRegistry.random();

    for ( int i = 0 ; i < l.size(); ++i ) {         
        paths.set(i, l.get(i));
    }

    //initial shuffle list of polygons
    for(int j=paths.length()-1; j>0;--j)
    {
        final int i = random.nextInt(j+1);
        final NestPath tmp=paths.get(i);
        paths.set(i, paths.get(j));
        paths.set(j, tmp);
    }

    return new NFP_Nesting(paths.toISeq(),binpol,binw,binh);

}

main:

public static void main(String[] args) {


    
    ExecutorService executor = Executors.newFixedThreadPool(1);

    NFP_Nesting nst = NFP_Nesting.of(tree,binPolygon,binWidth,binHeight);
    Engine<EnumGene<NestPath>,Double> engine = Engine
            .builder(nst)
            .optimize(Optimize.MINIMUM)
            .populationSize(config.POPULATION_SIZE)
            .executor(executor)
            .alterers(
                    new SwapMutator<>(0.25),
                    new PartiallyMatchedCrossover<>(0.35)
                    )
            .build();


    final EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();   

    Phenotype<EnumGene<NestPath>,Double> best=
            engine.stream()
            .limit(Limits.bySteadyFitness(5))
            .limit(Limits.byExecutionTime(Duration.ofSeconds(MAX_SEC_DURATION)))
            //.limit(10)
            .peek(NFP_Nesting::update)
            .peek(statistics)
            .collect(toBestPhenotype());

    System.out.println(statistics);
    //System.out.println(best);


}

I'm using Jenetics to nest a list of polygons using NoFitPolygon

I have a function that gived a list of polygon nests them following the order in the list.

I adapted the TravellingSalesman problem in order to have a genotype that represent the list of polygons, and during evolution the order change.

Now I want to add the rotation to the genotype, in order to get better results, but I don't know how to add it to my code.

Currently the order of the nestpaths determines the fitness, what i want to do is add, for every nestpath, a double value (doubleChromosome?) to the genotype that represent the rotation of the nestpath.

Nestpath is the class that represent the polygon

    public class NFP_Nesting implements Problem<ISeq<NestPath>, EnumGene<NestPath>, Double>{

static Phenotype<EnumGene<NestPath>,Double> tmpBest = null;
static Result tmpBestResult =null;

private NestPath _binPolygon;
Map<String,List<NestPath>> nfpCache=new HashMap<>();

private final ISeq<NestPath> _list;

public NFP_Nesting(ISeq<NestPath> lista,NestPath binpolygon ,double binw, double binh) 
{
    _binPolygon = binpolygon;
    _list=Objects.requireNonNull(lista);

}

@Override
public Codec<ISeq<NestPath>, EnumGene<NestPath>> codec() {
    return Codecs.ofPermutation(_list);
}

@Override
public Function<ISeq<NestPath>, Double> fitness() {

    return this::scalar_fitness;

}


/**
 * @param seq_nestpath
 * @return Fitness of the model
 */
Double scalar_fitness(final ISeq<NestPath> seq_nestpath) {

    List<NestPath> paths = seq_nestpath.asList();

    final Random random = RandomRegistry.random();
    
    //TODO NOT RANDOM ROTATION
    List<Integer> ids = new ArrayList<>();  
    for(int i = 0 ; i < paths.size(); i ++){
        ids.add(paths.get(i).getId());
        NestPath n = paths.get(i);
        if(n.getPossibleRotations()!= null)
        {
            n.setRotation(n.getPossibleRotations()[random.nextInt(n.getPossibleRotations().length)]);
        }
    }

///complicated function here

    return fitness;

}



private static NFP_Nesting of (List<NestPath> l, NestPath binpol, double binw, double binh)
{
    final MSeq<NestPath> paths = MSeq.ofLength(l.size());

    final Random random = RandomRegistry.random();

    for ( int i = 0 ; i < l.size(); ++i ) {         
        paths.set(i, l.get(i));
    }

    //initial shuffle list of polygons
    for(int j=paths.length()-1; j>0;--j)
    {
        final int i = random.nextInt(j+1);
        final NestPath tmp=paths.get(i);
        paths.set(i, paths.get(j));
        paths.set(j, tmp);
    }

    return new NFP_Nesting(paths.toISeq(),binpol,binw,binh);

}

Main:

public static void main(String[] args) {


    
    ExecutorService executor = Executors.newFixedThreadPool(1);

    NFP_Nesting nst = NFP_Nesting.of(tree,binPolygon,binWidth,binHeight);
    Engine<EnumGene<NestPath>,Double> engine = Engine
            .builder(nst)
            .optimize(Optimize.MINIMUM)
            .populationSize(config.POPULATION_SIZE)
            .executor(executor)
            .alterers(
                    new SwapMutator<>(0.25),
                    new PartiallyMatchedCrossover<>(0.35)
                    )
            .build();


    final EvolutionStatistics<Double, ?> statistics = EvolutionStatistics.ofNumber();   

    Phenotype<EnumGene<NestPath>,Double> best=
            engine.stream()
            .limit(Limits.bySteadyFitness(5))
            .limit(Limits.byExecutionTime(Duration.ofSeconds(MAX_SEC_DURATION)))
            //.limit(10)
            .peek(NFP_Nesting::update)
            .peek(statistics)
            .collect(toBestPhenotype());

    System.out.println(statistics);
    //System.out.println(best);


}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不及他 2025-02-02 07:38:56

我想我现在了解你的问题。您要做的是在基因型中编码额外的旋转。但是二聚体仅允许每个基因型一种基因类型。使用置换式codec,您将基因类型修复到enumgene,并且为了旋转,您将需要doublegene。通过一个简单的技巧,我们可以通过使用染色体内的基因顺序来表达路径置换为double -code

以下代码将向您展示如何执行此操作。

import static java.util.Objects.requireNonNull;

import java.util.function.Function;
import java.util.stream.IntStream;

import io.jenetics.DoubleChromosome;
import io.jenetics.DoubleGene;
import io.jenetics.Genotype;
import io.jenetics.MeanAlterer;
import io.jenetics.Phenotype;
import io.jenetics.SwapMutator;
import io.jenetics.engine.Codec;
import io.jenetics.engine.Engine;
import io.jenetics.engine.EvolutionResult;
import io.jenetics.engine.Limits;
import io.jenetics.engine.Problem;
import io.jenetics.example.NfpNesting.Solution;
import io.jenetics.util.DoubleRange;
import io.jenetics.util.ISeq;
import io.jenetics.util.ProxySorter;

public class NfpNesting implements Problem<Solution, DoubleGene, Double> {

    record NestPath() {}

    record Solution(ISeq<NestPath> paths, double[] rotations) {
        Solution {
            assert paths.length() == rotations.length;
        }
    }

    private final Codec<Solution, DoubleGene> code;


    public NfpNesting(final ISeq<NestPath> paths) {
        requireNonNull(paths);

        code = Codec.of(
            Genotype.of(
                // Encoding the order of the `NestPath` as double chromosome.
                // The order is given by the sorted gene values.
                DoubleChromosome.of(DoubleRange.of(0, 1), paths.length()),
                // Encoding the rotation of each `NestPath`.
                DoubleChromosome.of(DoubleRange.of(0, 2*Math.PI), paths.length())
            ),
            gt -> {
                /*
                The `order` array contains the sorted indexes.
                This for-loop will print the genes in ascending order.
                for (var index : order) {
                    System.out.println(gt.get(0).get(index));
                }
                */
                final int[] order = ProxySorter.sort(gt.get(0));

                // Use the `order` indexes to "permute" your path elements.
                final ISeq<NestPath> pseq = IntStream.of(order)
                    .mapToObj(paths::get)
                    .collect(ISeq.toISeq());

                // The second chromosome just contains your rotation values.
                final double[] rotations = gt.get(1)
                    .as(DoubleChromosome.class)
                    .toArray();

                return new Solution(pseq, rotations);
            }
        );
    }

    @Override
    public Codec<Solution, DoubleGene> codec() {
        return code;
    }

    @Override
    public Function<Solution, Double> fitness() {
        return solution -> {
            final ISeq<NestPath> paths = solution.paths();
            final double[] rotations = solution.rotations();

            // Do your fitness calculation.
            return 0.0;
        };
    }

    public static void main(final String[] args) {
        final var paths = ISeq.<NestPath>of();
        final var nesting = new NfpNesting(paths);

        final Engine<DoubleGene, Double> engine = Engine.builder(nesting)
            .alterers(
                new MeanAlterer<>(),
                new SwapMutator<>())
            .build();

        final Phenotype<DoubleGene, Double> best = engine.stream()
            .limit(Limits.bySteadyFitness(5))
            .collect(EvolutionResult.toBestPhenotype());

        System.out.println("Best Fitness: " + best.fitness());
        System.out.println("Best paths: " + nesting.decode(best.genotype()).paths());
    }

}

I think I understand your problem now. What you want to do is to have an additional rotation encoded in the genotype. But Jenetics only allows one gene type per genotype. Using the permutation-codec, you fixed the gene-type to a EnumGene and for your rotation you will need DoubleGene. With a simple trick we are able to express the path permutation also as DoubleGene, by using the order of the genes within the chromosome.

The following code will show you how to do this.

import static java.util.Objects.requireNonNull;

import java.util.function.Function;
import java.util.stream.IntStream;

import io.jenetics.DoubleChromosome;
import io.jenetics.DoubleGene;
import io.jenetics.Genotype;
import io.jenetics.MeanAlterer;
import io.jenetics.Phenotype;
import io.jenetics.SwapMutator;
import io.jenetics.engine.Codec;
import io.jenetics.engine.Engine;
import io.jenetics.engine.EvolutionResult;
import io.jenetics.engine.Limits;
import io.jenetics.engine.Problem;
import io.jenetics.example.NfpNesting.Solution;
import io.jenetics.util.DoubleRange;
import io.jenetics.util.ISeq;
import io.jenetics.util.ProxySorter;

public class NfpNesting implements Problem<Solution, DoubleGene, Double> {

    record NestPath() {}

    record Solution(ISeq<NestPath> paths, double[] rotations) {
        Solution {
            assert paths.length() == rotations.length;
        }
    }

    private final Codec<Solution, DoubleGene> code;


    public NfpNesting(final ISeq<NestPath> paths) {
        requireNonNull(paths);

        code = Codec.of(
            Genotype.of(
                // Encoding the order of the `NestPath` as double chromosome.
                // The order is given by the sorted gene values.
                DoubleChromosome.of(DoubleRange.of(0, 1), paths.length()),
                // Encoding the rotation of each `NestPath`.
                DoubleChromosome.of(DoubleRange.of(0, 2*Math.PI), paths.length())
            ),
            gt -> {
                /*
                The `order` array contains the sorted indexes.
                This for-loop will print the genes in ascending order.
                for (var index : order) {
                    System.out.println(gt.get(0).get(index));
                }
                */
                final int[] order = ProxySorter.sort(gt.get(0));

                // Use the `order` indexes to "permute" your path elements.
                final ISeq<NestPath> pseq = IntStream.of(order)
                    .mapToObj(paths::get)
                    .collect(ISeq.toISeq());

                // The second chromosome just contains your rotation values.
                final double[] rotations = gt.get(1)
                    .as(DoubleChromosome.class)
                    .toArray();

                return new Solution(pseq, rotations);
            }
        );
    }

    @Override
    public Codec<Solution, DoubleGene> codec() {
        return code;
    }

    @Override
    public Function<Solution, Double> fitness() {
        return solution -> {
            final ISeq<NestPath> paths = solution.paths();
            final double[] rotations = solution.rotations();

            // Do your fitness calculation.
            return 0.0;
        };
    }

    public static void main(final String[] args) {
        final var paths = ISeq.<NestPath>of();
        final var nesting = new NfpNesting(paths);

        final Engine<DoubleGene, Double> engine = Engine.builder(nesting)
            .alterers(
                new MeanAlterer<>(),
                new SwapMutator<>())
            .build();

        final Phenotype<DoubleGene, Double> best = engine.stream()
            .limit(Limits.bySteadyFitness(5))
            .collect(EvolutionResult.toBestPhenotype());

        System.out.println("Best Fitness: " + best.fitness());
        System.out.println("Best paths: " + nesting.decode(best.genotype()).paths());
    }

}
暗藏城府 2025-02-02 07:38:56

我不确定我是否完全了解您要解决的问题,但是置换编解码器(codecs.ofpermunt(seq))用于给定对象序列的顺序确定它的问题健康。因此,只有nestPath的顺序 iSeq&lt; nestPath&gt;的元素定义了健身,对吗?健身功能不负责通过副作用更改对象。

我也不明白您对基因型旋转旋转的意思。 em> Jenetics 中的A 基因型 JUST 的一系列染色体。也许您可以更详细地解释您的优化问题。

对您的代码本身的一些注释

  • nfp_nesting :: of对给定的list&lt; nestpath&gt;进行改组。这不是必需的。
  • 使用.peek(NFP_NESTING :: UPDATE)进行一些更新,也看起来可疑。如果您需要更新NestPath对象,则不再进行排列优化。 NestPath对象应该是不可变的。
  • 不要将任何 static 变量存储在问题实现中。 问题接口仅组合codec和健身功能,应该是不可变的。

因此,如果您可以更清楚地解释您的问题,我可以尝试帮助找到适当的编码。

I'm not sure whether I fully understand the problem you want to solve, but the permutation codec (Codecs.ofPermutation(Seq)) is used for problems where the order of a given sequence of objects determines it's fitness. So, only the order of the NestPath elements in ISeq<NestPath> defines the fitness, right? The fitness function is not responsible for altering your objects, via side effects.

I also don't understand what you mean with rotate the genotype. A Genotype in Jenetics is just a sequence of chromosomes. Maybe you can explain your optimization problem in a greater detail.

Some comments to your code itself

  • The NFP_Nesting::of does a shuffling of the given List<NestPath>. This is not necessary.
  • Doing some updates with .peek(NFP_Nesting::update) also looks suspicious. If you need to update your NestPath objects, you no longer doing a permutation optimization. The NestPath object should be immutable.
  • Don't store any static variables in your Problem implementation. The Problem interface just combines the Codec and the fitness function and should be immutable.

So, if you can explane your problem more clearly, I can try to help to find a proper encoding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文