Keywords

1 Introduction

Last-In-First-Out (LIFO) type storage is used in logistics and assembly systems, where a high degree of storage efficiency is required. Application scenarios include part shelves in assembly, automated guided vehicles in matrix production [1] and in general warehousing.

A particular optimization problem of this storage type is the reduction of item shuffling, that is the reduction of item relocation in order to clear access to an item that is to be retrieved. In an optimal case the item would always be at the front of the respective strip. However this can only be guaranteed if the strip is homogeneous in terms of item types. As described in [2, 3] certain types of industries such as food, medical and chemicals this is not always possible due to expiration dates and production batch requirements. Furthermore a type-pure homogeneous storage would assume enough strips to handle both all item types as well as any potential backlog thereof, which is unrealistic in many application scenarios.

Usually, an attempt is made to describe this problem mathematically and solve it by the means of Linear Programming (LP) problem such as described in [4]. Many works are grouped under the term Storage Location Assignment Problem—SLAP, many of which do not explicitly consider the LIFO topology. In a previous paper [2], we presented an approach that deals precisely with the problem of optimizing this type of a LIFO storage using metaheuristics. In this paper, we would like to discuss the structure and further development of the data structure, as well as the effects of the different approaches.

The original motivation of this work was the optimization of a LIFO type palette warehouse of a beverage producer. However given the aforementioned further application scenarios and little research work on this subject it was decided to further generalize the approach as we see potential in its use in adaptable assembly systems.

We first define the model used for the algorithm, the prior work done and give a brief overview of the theoretical basis. Subsequently we describe the evolution of the data structure used and the convergence behavior as well as the concepts of exploitation versus exploration with the said data structure.

2 Problem Description

The general model concerned with this optimization problem is that of a LIFO type storage consisting of an arbitrary amount of strips. Each strip acts like an individual LIFO row, in that items can only be removed in the reverse sequence of them being stored. This mirrors a typical generalized application scenario of LIFO storage, such as palette warehousing.

Following a similar definition as [3], let W be a storage composed of \(n_s\) strips, \(W=\{1,...,n_s\}\) which are each may contain \(n_i\) items \(W_i=(s_1,...)\). Given a sequence of \(n_z\) items to be placed into the storage \(Z=(z_1, ...)\) The goal is to find a configuration for the placement of the items in the storage, such that using a scoring method \(f(W)\rightarrow \mathbb {R}\) that the latter sits at Pareto optimality.

The implementation of f(W) depends on the desired properties and can be implemented to examine single items, strips or the storage as a whole. Depending upon the formulation this can represent a multi-objective optimization problem. For example [2, 5] describe possible variants examining the homogeneity of strips in various manners and their combination to a single score. Further multi-dimensional approaches could further assess the access to items through empty neighbouring strips.

3 Previous Works

Current research approaches consider single item allocation, such as [3] with an ad-hoc placement strategy and a greedy relocation procedure, [5] with a genetic algorithm refined with simulated annealing or [4] with a linear model. However in those algorithms the placement of only single items is being considered, restricting the view of potential storage optimality that the consideration of multiple items could offer.

It is therefore advantageous to optimize the storage allocation for multiple items at once. This allows the algorithm for example to take into account the current production schedule. In the previous work [2] we present an approach to solve the allocation problem for an ordered batch of items. The focus of the latter was on illustrating and explaining the problem in form of an implementation of a genetic algorithm. The implementation of typical storage restrictions in terms of the fitness function formulation was furthermore handled in detail and mathematically described. It should be noted that the way in which the fitness methods are implemented has a significant influence on the runtime and parameterisation of the algorithm.

This approach has been developed in the Python programming language based a genetic algorithm module. The latter module was extended by a number of adapted fitness, crossover and motivation methods. A meta class inherits the original genetic algorithm module and overloads certain functions with extensions with regards to the LIFO data structures as described below, debugging and profiling functionality. Using an application programming interface (API) real-time data from a regional beverage producer who uses such a LIFO storage was used to test the approach using a real scenario. The latter contains storage capacities of up to 5000 pallets, at a varying strip size with up to 30 pallets. The number of pallets to have their storage location optimized are taken from a production queue which varies between 8 and 12 pallets.

4 Theoretical Basis

4.1 Biological Model and Basic Idea

The idea of genetic algorithms is inspired by evolutionary processes in nature, through which individuals adapt more increasingly to environmental conditions. The principle of which is described e.g. in [6, 7], goes back to Charles R. Darwin, who proclaimed it as “survival of the fittest”. The basic idea of transferring this approach to mathematical optimisation problems goes back to a work by [8] as a method of metaheuristics.

As an evolutionary optimisation method, the solution is represented by an individual in genetic algorithms. Multiple individuals together build a population and thereby a set of solutions in a search space.

The individuals of each generation must be characterised with regards to the problem under consideration for solution quality. This task is usually performed by a fitness function that quantifies the quality of an individual with the use of a real value.

Corresponding to the biological mechanisms of crossing, mutation and selection, there are also methods to enable the population of individuals to evolve.

4.2 Structure and Function of the Genetic Algorithm

For a better understanding we first briefly review the workings of a genetic algorithm in this section. The algorithm consists mainly of the following components and phases. These phases are executed in an iterative manner:

  1. 1.

    representation (definition of individuals),

  2. 2.

    initialization

  3. 3.

    evaluation function (fitness function),

  4. 4.

    variation operators like recombination and mutation,

  5. 5.

    selection mechanism,

  6. 6.

    Repeat from step 3 until a stop criteria is reached.

The first step of an evolutionary algorithm like genetic algorithm is to define a description or representation of the context and the search space of the problem. This often involves simplifying or abstracting a real-world problem to derive a clearly defined context. It must be decided how a possible solution should be coded and stored so that it can be processed by a computer in the given programming language. Simple problems are often implemented in the form of binary permutations, so called genotype representations. More complex problems, must be implemented using more complex data types, as simple binary encoding is no longer sufficient. In this case, several structures are often used to map the relationships.

After coding the problem, the next step is to initialise a start population randomly. After initialising a starting population, the fitness of the individuals is calculated using a suitable fitness function.

A selection method is used to pick out a given number of the fittest individuals from the current population in order for them to be transferred into the next population. This usually takes into account a stochastic component when selecting the fittest individuals [6, 9].

During recombination, new individuals are generated from two selected individuals with a crossover operator. From the newly emerged individuals, candidates for mutations are selected with a low probability to strengthen the exploration of the search space. Mutation involves changing a random part of the individual. Various mutation methods are evaluated in [10]. Depending on the coding chosen, a mutation method has a different impact on exploration, depending upon the problem certain mutation operations are not effective and produce useless solutions in the search space [9].

5 Data Structure

The data structure in the previous work [2] was initially chosen in such a way, that standard crossover and mutation operators for the traveling salesman problem such as described in [6] can be applied, yet such that the interpretation of the data structure keeps track of the LIFO principle and the item sequence.

This originally was implemented as two vectors, one map vector in which every element would correspond to an empty slot in the LIFO storage in terms of the strip number. That is if a strip i has n free slots the vector would contain n elements with value i. A further vector, the individual of an equal size and corresponding by index to the map vector, would be occupied either by an empty indicator or by an identifier for the item to be placed (Fig. 1).

Fig. 1
figure 1

Sparse- and dense data structure for the same item configuration. Shaded boxes in the storage are occupied, empty boxes are free. Numbered vector elements are strip indices

This individual vector would then be interpreted sequentially from left-to-right by skipping over empty elements and pushing items into the farthest free position from the front of the corresponding strip. This is illustrated in Algorithm 1 for an individual vector I, a map vector M which are both of size n, as well as a function to push the item onto the back of a strip pushToStip(strip, item).

figure a

Standard mutation and crossover operators, need a continuous vector filled with values. In order to facilitate the use of those operators another vector would be generated from the individual in which all empty element indicators are filled with values that are distinct from from the item identifiers.

After the application of the standard operator the filled in values are replaced again with empty element indicators, such that the resulting data structure matches the representation as described above.

A problem with this data structure is that due to the large sparsity of the vector probabilistic selection methods will often pick empty elements. Attempts were made to overcome such problems by having probabilistic operations only choose from occupied elements by deriving an indexed vector of the non-empty elements such as described in the concepts of [11].

Furthermore attempts were made to minimize the vector size in overall, by limiting the amount of free slot elements per column to the maximum amount of items to be placed, or filtering out the worst scoring strips.

In order to address these issues the data structure was redesigned such that the individual vector is a standard dense vector. In this approach the map vector has the size of the items to be stored and their identifiers. The individual vector on the other hand then contains the strip numbers, the number of free slots per strip is stored in a separate data structure which is implemented using a standard dictionary. Care needs to be taken to ensure that the individual vector only contains each strip index at a maximum amount of the free slots in that strip. The latter requires special handling for the initial population generation and mutation operators.

This vector is still interpreted from left-to-right, in order to maintain the storage order, following the same terminology as for Algorithms 1 and 2 shows how this structure is mapped into a storage.

figure b

In this approach the crossover and mutation functions need to be significantly adjusted to handle and modify the vector. In particular a mutation function that does not merely swap elements will need to ensure that when altering the strip index that the total amount of occurrences of the latter in the individual are less than or equal to the amount of free slots in the strip. This can be achieved by first counting the free slots for every strip in the storage and then subtracting and removing the slots claimed by the individual. The mutation can then select a new strip index from the remaining ones.

In order to use standard crossover functions distinct values are required, this can be achieved by operating on a shadow vector with increasing values representing the indices of the individual vector. Upon applying the crossover to the shadow vector it is then used as a permutation to the individual.

6 Convergence Behavior

The convergence behavior can be assessed both in terms of computational performance and maximum achieved optimality. In order to provide comparable results for the data structure approaches, a snapshot of a warehouse configuration from a beverage manufacturer was taken and used to validate the performances.

In order to provide performance improvements the fitness of all strips in the storage as-is are computed upfront. During the execution of the algorithm the fitness is only recomputed for strips into which items have been designated to, in accordance to the configuration of the individual. This allows fast computation of the fitness score for the whole storage. This results in a predictable performance pattern, where if items are clustered, with an iteratively decreasing spread across the storage, the execution time of the fitness function over the population decreases. This behavior can be examined in Figs. 2 and 3. This pattern applies to either data structure used, with the sparse structure having a significantly higher offset time than the dense structure, with the former taking 10 to 20 times longer to compute than the dense method.

Fig. 2
figure 2

Average fractional execution time of the different steps in the genetic algorithm using the dense vector approach from around 100 executions

In terms of absolute performance, the choice of data structures, in particular for dictionary or map type containers that are used for various lookup operations can significantly affect the performance. However in this case either algorithm was implemented using standard Python language container data structures, as such the performance increase is in a relative relation.

In terms of the optimality the algorithm sometimes gets stuck in a local maximum. Using an elitist genetic algorithm, this can result in multiple generations without improvement followed by erratic jumps. This behavior presents a challenge for an appropriate stop criterion. In the current algorithm a defined amount of the last n fitness values are being kept and examined for a sufficient change \(\delta \). Once this falls below a threshold the algorithm is stopped. Currently it is found that appropriate values are to examine the fitness scores of the last 20 generations to have a change of at least 0.01 if the fitness score is in a range of [−1,1].

Fig. 3
figure 3

Convergence behavior of the dense vector approach using exploitation only and both exploitation and exploration. The higher the convergence score, the better

7 Exploration vs. Exploitation

In a genetic algorithm, the mutation methods have the task of introducing new entropy to an individual in order to expand the search space within a generation, this is called the exploration. The crossover method on the other hand is in charge of combining the best aspects of two individuals in order to inherit an improvement into the next generation, this is the exploitation. Without mutation methods and purely with crossover methods, there is a risk that the algorithm will remain in a local extremas. The algorithm without crossover methods on the other hand will be probabilistic when based solely on the mutation methods.

As far as the nature of the mutation function is concerned, it is noted that the structure of the data leads to significant differences in terms of exploration in the prior described model. If the problem is represented in the form of a single sparse vector, mutation methods on their own are able to generate a proper exploration rate. This is the result of the vector attaining a new configuration by randomly shuffling the elements around. If the data structure however is implemented in the form of a condensed vector as described above for the new approach, exploitative mutation methods that shuffle elements such as CIM and RSM as described in [10] offer little to no exploration. This is due to the dense vector approach only containing a subset of the possible configurations and as such not expanding the search space beyond what was initially generated with the individual. In this case in order to obtain a desired exploration rate new configurations need to be introduced, this can be achieved with mutation methods that not merely shuffle elements around but also can alter them, an example of which is the Twors mutation [10]. Figure 3 illustrates the behavior of the dense vector approach when using only exploitative versus explorative mutation methods.

8 Discussion

The method described herein assumes that the strips are constrained to insertion and removal from the front only in a true Last-In-First-Out fashion. Methods to use the neighbouring strips to access items are not discussed, but could be further considered in the fitness methods, if applicable. This approach still considers all items as single entities, even if they are of the same type. A further refinement could be to consider clusters of items in order to improve convergence behavior and item location quality on otherwise sub-optimal cases.

As mentioned, the stopping criteria is a particular problem for this type of algorithm. Advanced methods utilizing early stopping techniques such as described in [12] were not further explored or evaluated for their applicability in this context.

The size of the population in relation to the size of items to be stored as well as the size of the storage has not mathematically quantified. As a consequence of this the population size is based on intuition or trial and error.

By comparison to the sparse vector approach the dense vector approach yields a significant performance saving impact at the cost of a higher complexity. This results in the dense approach being harder to assess in its theoretical performance by comparison to the sparse vector approach.

Further research could be conducted in order to explore the addition of memetic algorithm approach based on the work of [13] in which individuals are further refined.

Adaptive assembly systems allow many degrees of flexibility but are inherently complex in their optimization, we hope to adapt the described algorithm for this usage scenario. But due to the inherent complexity of adaptive assembly systems we explore this approach first using more simplistic but real world usable application scenarios.