Search code examples
javagenetic-algorithm

Can I store different values in an object's field depending on the object it is called from?


I work on a genetic algorithm for a robotic assembly line balancing problem (assigning assembly operations and robots to stations to minimize the cycle time for a given number of stations). The solution is represented by an ArrayList (configuration) which holds all the operations in the sequence assigned to different stations. Furthermore, I have two more ArrayLists (robotAssignment, operationPartition) which indicate where a new station starts and which robot is assigned to a station. For example, a solution candidate looks like this (configuration, robotAssignment, operationPartition from top to bottom):

Initial cycle time: 50.0
|2|7|3|9|1|5|4|6|8|10|
|2|1|3|2|
|0|2|5|7|

From this representation we know that operations 3, 9, and 1 are assigned to station 2 and robot 1 is used since operationPartition gives the starting index of a new station in configuration.

With the help of the ArrayList operationPartition I can always figure out the station of an operation. However, I would prefer to store the station index in the an object of the class Operation itself. I created a class Operation with a class variable stationIndex. All operations are added to another class OperationManager which holds all operations in an ArrayList. My class Configuration is used to create a new configuration and include all operations from the OperationManager.

My problem is that I can store the stationIndex of an operation only once and not for each configuration (at least I could not figure how to do this). To give you an example lets assume we have two configurations:

    Configuration conf1 = new Configuration();
    Configuration conf2 = new Configuration();
    conf1.generateIndividual();
    conf2.generateIndividual();

Now, if I change the stationIndex of operation1 in conf1 it is also changed in conf2 since this variable "belongs" to the operation and does depend on the configuration.

Is there any way to store different values in the stationIndex depending on the configuration? This would be my preferred solution if this is somehow possible.

public class Operation {
    int[] predecessors;
    int stationIndex;


// Construct an operation with given predecessors
public Operation(int[] predecessors){
    this.predecessors = predecessors;

}


// Get operations's predecessors
public int[] getPredecessors() {
    return this.predecessors;
}

// Set operations's station index
public void setStationIndex(int stationIndex){
    this.stationIndex = stationIndex;
}

// Get operations's station index
public int getStationIndex(){
    return this.stationIndex;
}

Class OperationManager:

public class OperationManager {

// Holds our operations
private static ArrayList operations = new ArrayList<Operation>();

// Adds an operation
public static void addOperation(Operation operation) {
    operations.add(operation);
}

// Get an operation
public static Operation getOperation (int index){
    return (Operation)operations.get(index);
}

// Get index of an operation
public static int getOperationIndex(Operation operation) {
    return operations.indexOf(operation);
}

// Get the number of operations
public static int numberOfOperations() {
    return operations.size();
}

Class Configuration (not complete but with all relevant parts):

public class Configuration {

int initialCycleTime = RobotManager.calcLowerBound();

// Holds our array of operations
private ArrayList configuration = new ArrayList<Operation>();
private ArrayList robotAssignment = new ArrayList<Robot>();
private ArrayList operationPartition = new ArrayList<Integer>();

// Cache
private int fitness = 0;

// Constructs a blank configuration
public Configuration() {
    for (int i = 0; i < OperationManager.numberOfOperations(); i++) {
        configuration.add(null);
    }

    for (int i = 0; i < GA_RALBP.numberOfStations; i++) {
        operationPartition.add(null);
    }

    for (int i = 0; i < GA_RALBP.numberOfStations; i++) {
        robotAssignment.add(null);
    }

}

// Creates a random individual
public void generateIndividual() {
    // Loop over all operations and add them to our configuration
    for (int operationIndex = 0; operationIndex < OperationManager.numberOfOperations(); operationIndex++) {
        setOperation(operationIndex, OperationManager.getOperation(operationIndex));
    }
    // Randomly shuffle the configuration
    Collections.shuffle(configuration);
}

Solution

  • Either station index is part of an Operation object or not.

    If station index is part of an Operation object, then you'll need to represent the same operation with multiple Operation objects, since you want the Operation object in one configuration to hold a different station index in one configuration than another. You could make that happen in Configuration.generateIndividual() by cloning the object you get back from OperationManager.getOperation().

    Alternatively, you could remove station index from Operation objects. For example, you could represent the station index by the operation's position in the list in Configuration.