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 * 1.候補のうち、一番タスクが積まれていないものに前から積む
020 * 2.同じであればリストの先頭の方に割り当てられる
021 * 3.納期オーバーの場合は評価関数の値が小さくなるようにする
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                        for( int j=0; j<machines.length; j++ ){
092                                if(!machineList.containsKey( machines[j] )){
093                                                machineList.put( machines[j], Double.valueOf(0) );                              // 6.8.2.3 (2017/11/10)
094                                                taskSchedule.put( machines[j], new ArrayList<String>() );
095                                }
096
097                                if( machineList.get(machines[j]) < work){
098                                        work = machineList.get(machines[j]);
099                                        hitMachine = machines[j];
100                                }
101                        }
102
103                        machineList.put( hitMachine, Double.valueOf(work + chrom.getAttr()) );          // 総工数 6.8.2.3 (2017/11/10)
104                        taskSchedule.get( hitMachine ).add( chrom.getName() );  // 割りついたタスクリスト
105
106                        if( work + chrom.getAttr() > noki ){
107                                nokisum += noki - work + chrom.getAttr();                       // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
108                        }
109                }
110                return nokisum;
111        }
112
113        /**
114         * 自身のクラスを新たに作成するメソッド。
115         * 
116         * ここではオプションデータはクローンせずに参照で渡しています。
117         * (計算では利用していません)
118         * 
119         * @param repr 染色体表現
120         * @return 作成された自分自身のクラス
121         */
122        @Override
123        public AbstractHybsGAChromosome newFixedLengthChromosome(final List<HybsGAObject> repr) {
124                final HybsScheduleChromosome rtn = new HybsScheduleChromosome(repr);
125                rtn .setOptionData( optionData );
126                return rtn;
127        }
128
129        /**
130         * 染色体表現のチェック。
131         * 
132         * @param repr HybsGAObjectのリスト
133         */
134        @Override
135        protected void checkValidity(final List<HybsGAObject> repr) throws InvalidRepresentationException {
136                // Listの中身のチェックをする箇所。必要であれば記述する
137        }
138}