首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Jenetics筑巢的定制基因型

Jenetics筑巢的定制基因型
EN

Stack Overflow用户
提问于 2022-05-05 13:17:42
回答 2查看 90关注 0票数 0

我使用Jenetics来嵌套一个多边形列表,使用NoFitPolygon

我有一个函数,按照列表中的顺序给出了多边形嵌套的列表。

我适应了TravellingSalesman问题,以便有一个代表多边形列表的基因型,并且在进化过程中顺序发生变化。

为了获得更好的结果,我想把旋转添加到基因型中,但是我不知道如何将它添加到代码中。

目前,嵌套路径的顺序决定了适合度,我要做的是为每个嵌套路径添加一个双值(doubleChromosome?)表示巢径旋转的基因型。

内路径是表示多边形的类。

代码语言:javascript
复制
    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

代码语言:javascript
复制
    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:

代码语言:javascript
复制
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);


}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-05-07 12:34:35

我想我现在明白你的问题了。你想要做的是有一个额外的旋转编码在基因型。但是Jenetics只允许每种基因型有一种基因类型。使用置换编解码器,将基因类型固定为EnumGene,在旋转时需要DoubleGene。通过一个简单的技巧,我们可以通过利用染色体内基因的顺序来表达路径置换,也就是DoubleGene

下面的代码将向您展示如何做到这一点。

代码语言:javascript
复制
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());
    }

}
票数 0
EN

Stack Overflow用户

发布于 2022-05-05 15:15:04

我不确定我是否完全理解您想要解决的问题,但是置换编解码器(Codecs.ofPermutation(Seq))用于处理给定对象序列的顺序决定其适合性的问题。因此,只有NestPath元素在ISeq<NestPath>中的顺序定义了适应度,对吗?健身功能不负责改变你的对象,通过副作用。

我也不明白你旋转基因型是什么意思。Jenetics中的Genotype只是一系列染色体。也许您可以更详细地解释您的优化问题。

对代码本身的一些注释,

  • NFP_Nesting::of对给定的List<NestPath>进行洗牌。这不是necessary.
  • Doing,有些.peek(NFP_Nesting::update)的更新看起来也很可疑。如果需要更新NestPath对象,则不再执行排列优化。immutable.
  • Don't对象应该是NestPath,在Problem实现中存储任何静态变量。Problem接口只是将Codec和适应度函数结合在一起,应该是不可变的.

所以,如果你能更清楚地解释你的问题,我可以帮助你找到一个合适的编码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72127848

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档