    001package org.opengion.penguin.math.ga;
    002
    003import java.util.ArrayList;
    004import java.util.List;
    005import java.util.Map;
    006import java.util.HashMap;
    007import java.util.Collections;                   // 6.9.8.0 (2018/05/28)
    008
    009import org.apache.commons.math3.genetics.InvalidRepresentationException;
    010
    011/**
    012 * AbstractHybsGAChromosomeのサンプル実装クラスです。
    013 * HybsGAObjectImplを利用しています。
    014 * 属性値配列(文字列)にタスクの割当先（機械や人）候補
    015 * 属性値（実数）にこのタスクにかかる時間
    016 * 属性値配列（実数）[0]にこのタスクの納期（開始からの経過時間）
    017 * を持たせているという想定です。
    018 * このクラスでは次のようにスケジュールを決めます。
    019 * １．候補のうち、一番タスクが積まれていないものに前から積む
    020 * ２．同じであればリストの先頭の方に割り当てられる
    021 * ３．納期オーバーの場合は評価関数の値が小さくなるようにする
    022 *
    023 */
    024public class HybsScheduleChromosome extends AbstractHybsGAChromosome {
    025
    026        /**
    027         * コンストラクタ。
    028         */
    029        public HybsScheduleChromosome() { super(); }            // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    030
    031        /**
    032         * コンストラクタ。
    033         *
    034         * @param representation 染色体表現
    035         */
    036        public HybsScheduleChromosome(final List<HybsGAObject> representation) {
    037                super(representation);
    038        }
    039
    040        /**
    041         * 適合度計算。
    042         *
    043         * @return 適合度計算の結果
    044         */
    045        public double fitness() {
    046                final List<HybsGAObject>                representation  = getRepresentation();
    047                final Map<String,Double>                machineList             = new HashMap<>();              //名前は機械リストだが、人でも良い
    048                final Map<String, List<String>> taskSchedule    = new HashMap<>();
    049
    050                // 実際にスケジュールの積み上げを行い、納期遅れの合計を出します
    051                // 6.9.8.0 (2018/05/28) 変数手直し
    052//              double nokisum = 0.0;
    053//              nokisum = makeSchedule( representation, machineList, taskSchedule );
    054                final double nokisum = makeSchedule( representation, machineList, taskSchedule );
    055
    056//              // リストから最大値を取得する(出てくる順番は問わない)
    057//              double maxWork=0;
    058//              for( final String mw : machineList.keySet() ){
    059//                      maxWork = machineList.get(mw) > maxWork ? machineList.get(mw) :maxWork;         // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    060//              }
    061
    062                // リストから最大値を取得する(出てくる順番は問わない)
    063                // 6.9.8.0 (2018/05/28) 処理手直し
    064                final double maxWork = Collections.max( machineList.values() );
    065
    066                return 1 / ( maxWork + nokisum*nokisum); //納期遅れが多くなるとどんどん値が小さくなるように評価する
    067        }
    068
    069        /**
    070         * HybsGAObjectImplを利用して前からスケジュールを積み上げていきます。
    071         *
    072         * @og.rev 6.8.2.3 (2017/11/10) Doubleｲﾝｽﾀﾝｽ作成方法の変更。
    073         *
    074         * @param representation 染色体表現
    075         * @param machineList マシンに対する積み上げ工数のリスト。(書き込まれるのでfinalにしない）
    076         * @param taskSchedule マシンに対して、前からタスクをセットするリスト。(書き込まれるのでfinalにしない）
    077         * @return 納期遅れの累計
    078         */
    079        public double makeSchedule( final  List<HybsGAObject> representation , final Map<String,Double> machineList, final Map<String, List<String>> taskSchedule){
    080                HybsGAObjectImpl chrom;
    081                double nokisum = 0.0;
    082
    083                for ( int i=0; i<representation.size(); i++){
    084                        chrom = (HybsGAObjectImpl)representation.get(i);
    085
    086                        final String[] machines = chrom.getAttrStrArray();
    087                        // ここでスケジュールを当てはめていく
    088                        final double   noki = chrom.getAttrArray()[0];
    089                        String hitMachine = null;
    090                        double work=999999999;
    091                        // 7.2.9.4 (2020/11/20) PMD:This for loop can be replaced by a foreach loop
    092                        for( final String mach : machines ){
    093                                if(!machineList.containsKey( mach )){
    094                                        machineList.put( mach, Double.valueOf(0) );                             // 6.8.2.3 (2017/11/10)
    095                                        taskSchedule.put( mach, new ArrayList<String>() );
    096                                }
    097
    098                                if( machineList.get(mach) < work){
    099                                        work = machineList.get(mach);
    100                                        hitMachine = mach;
    101                                }
    102                        }
    103//                      for( int j=0; j<machines.length; j++ ){
    104//                              if(!machineList.containsKey( machines[j] )){
    105//                                              machineList.put( machines[j], Double.valueOf(0) );                              // 6.8.2.3 (2017/11/10)
    106//                                              taskSchedule.put( machines[j], new ArrayList<String>() );
    107//                              }
    108//
    109//                              if( machineList.get(machines[j]) < work){
    110//                                      work = machineList.get(machines[j]);
    111//                                      hitMachine = machines[j];
    112//                              }
    113//                      }
    114
    115                        machineList.put( hitMachine, Double.valueOf(work + chrom.getAttr()) );          // 総工数 6.8.2.3 (2017/11/10)
    116                        taskSchedule.get( hitMachine ).add( chrom.getName() );  // 割りついたタスクリスト
    117
    118                        if( work + chrom.getAttr() > noki ){
    119                                nokisum += noki - work + chrom.getAttr();                       // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    120                        }
    121                }
    122                return nokisum;
    123        }
    124
    125        /**
    126         * 自身のクラスを新たに作成するメソッド。
    127         *
    128         * ここではオプションデータはクローンせずに参照で渡しています。
    129         * (計算では利用していません）
    130         *
    131         * @param repr 染色体表現
    132         * @return 作成された自分自身のクラス
    133         */
    134        @Override
    135        public AbstractHybsGAChromosome newFixedLengthChromosome(final List<HybsGAObject> repr) {
    136                final HybsScheduleChromosome rtn = new HybsScheduleChromosome(repr);
    137                rtn .setOptionData( optionData );
    138                return rtn;
    139        }
    140
    141        /**
    142         * 染色体表現のチェック。
    143         *
    144         * @param repr HybsGAObjectのリスト
    145         */
    146        @Override
    147        protected void checkValidity(final List<HybsGAObject> repr) throws InvalidRepresentationException {
    148                // Listの中身のチェックをする箇所。必要であれば記述する
    149        }
    150}