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);
}
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
.