/**********************************************************************
# Copyright (c) EWA Systems Inc. 1998 - 2005 All Rights Reserved
#               No part of this program may be photocopied, reproduced,
#               or translated to another programming language without
#               the prior written consent of EWA Systems.
**********************************************************************/

package com.ewasystems.opt.ga.test;

import com.ewasystems.opt.ga.GeneticAlleleSet;
import com.ewasystems.opt.ga.GeneticEngine;
import com.ewasystems.opt.ga.GeneticGene;
import com.ewasystems.opt.ga.GeneticProblem;
import com.ewasystems.opt.ga.GeneticRunTask;

/**
 * <p>Genetic Algorithm Test Case: Multi Knapsack</p>
 * <p>Description: Maximize Value in Limited Weight Backpack where
 * Value differs between Backpacks</p>
 * <p>Copyright: EWASystems Copyright (c) 1998 - 2005</p>
 * <p>Company: EWASystems</p>
 * @author Lincoln Evans-Beauchamp
 * @version 1.0
 */
public class MultiKnapsack extends GeneticProblem
{
  /** Backpack Weight Limit */
  protected int weightLimit = 625;
  /** Object Weights */
  protected int[] objectWeights = new int[150];
  /** Object Values */
  protected double[][] objectValues = new double[150][3];

  /**
   * Problem Constructor
   */
  public MultiKnapsack()
  {
    super("3 Knapsacks 150 Objects", "Minimize f(x) = 1/4000*sum(x(i)-100)^2 - prod((x(i)-100)/sqrt(i)) + 1 where X = [-600, 600] by .02");

    for (int i=0; i<150; i++)
    {
      objectWeights[i] = (int)(10d + 10d*Math.random());
      objectValues[i][0] = (int)(100d*Math.random());
      objectValues[i][1] = (int)(100d*Math.random());
      objectValues[i][2] = (int)(100d*Math.random());
    }
  }

  /**
   * The Objective Function
   * @param gene The Genetic Gene to Test
   * @return double: The Genetic Gene's Fitness
   */
  public double f(GeneticGene gene)
  {
    double[] wt = new double[3];
    double value = 0d;
    for (int i=0; i<gene.getGeneLength(); i++)
    {
      String x = (String)gene.getGeneValue(i);
      if (x.equals("1"))
      {
        wt[0] += objectWeights[i];
        value += objectValues[i][0];
      }
      if (x.equals("2"))
      {
        wt[1] += objectWeights[i];
        value += objectValues[i][1];
      }
      if (x.equals("3"))
      {
        wt[2] += objectWeights[i];
        value += objectValues[i][2];
      }
      if (wt[0] > weightLimit) return 0d;
      if (wt[1] > weightLimit) return 0d;
      if (wt[2] > weightLimit) return 0d;
    }
    return value;
  }

  /**
   * Gets the Allele Set for the Problem
   * @return GeneticAlleleSet: The Allele Set
   */
  public GeneticAlleleSet getAlleleSet()
  {
    GeneticAlleleSet gas = new GeneticAlleleSet();
    String[] values = new String[] {"N", "1", "2", "3"};
    gas.addCategoricalAllele("N123", values, 150);
    return gas;
  }

  /**
   * Gets the Objective Type
   * @return int: The Objective Type
   */
  public int getObjectiveType()
    {return OBJECTIVE_TYPE_MAX;}

  /**
   * Main for Running the Problem
   * @param args Not Used
   */
  public static final void main(String[] args)
  {
    GeneticEngine ge = new GeneticEngine();
    GeneticRunTask grt = ge.createGeneticTask(new MultiKnapsack());
    grt.getConfig().setShowFinalReport(true);
    grt.run();
    double[] wt = new double[3];
    for (int i=0; i<grt.getResultGeneLength(); i++)
    {
      if (((String)grt.getResultGeneValue(i)).equals("1"))
        {wt[0] += ((MultiKnapsack)grt.getProblem()).objectWeights[i];}
      if (((String)grt.getResultGeneValue(i)).equals("2"))
        {wt[1] += ((MultiKnapsack)grt.getProblem()).objectWeights[i];}
      if (((String)grt.getResultGeneValue(i)).equals("3"))
        {wt[2] += ((MultiKnapsack)grt.getProblem()).objectWeights[i];}
    }
    System.out.println("WT 0 = "+wt[0]);
    System.out.println("WT 1 = "+wt[1]);
    System.out.println("WT 2 = "+wt[2]);
  }
}

