Search code examples
optimizationintegerparticles

How to teak Particle swarm to have unique values in every particle after velocity update, where some value must be integer and some float


I am trying to solve PSO (Particle Swarm Optimisation) to have a particle where some values must be integers and must be unique and some are float (may not be unique) e.g. a solution like this is desirable after every velocity update: {0,2,1,5,4,6,8,7,0.087,0.345} The first eight values must be unique and integers and last two can be regular updates. The problem I am having is that after velocity update the first eight values tend to duplicate like e.g.: {0,0,1,2,3,4,5,6,7,0.76,0.345}. How this can be achieved? Your help is much appreciated. Thank you


Solution

  • After the velocity (and position) update for a single particle, I assume you perform some discretisation of the first 6 of the 8 (position?) values to transform them from floating points to integers. In this step, you need to define a measure to ensure the uniqueness of the integer numbers.

    Lets say, for some particle i, that we have the following position matrix after the velocity update (leaving out the 7th and 8th entry)

    posVector(particle i) = {0.1, -0.2, 1.3, 6.2, 2.4, 1.6}.
    

    If we just round these number, we would end up with integers

    posVectorInt(particle i) = {0, 0, 1, 6, 2, 2},
    

    in which the entries are non-unique. One simple way to fix this would be to, prior to transforming float->int, ranking the numbers in position 1 through 6, e.g., w.r.t. increasing value, as

    posVectorRank(particle i) = {2, 1, 3, 6, 5, 4}.
    

    Next, we could start rounding particles, starting with rank 1, but, from rank 2 and onwards, ascertaining that the rounded value is not equal to the previously rounded value. In some pseudo/mixed-code,

    // Rank 1 rounding
    for entry in posVectorRank where posVectorRank(entry) = 1 
        posVector(entry) = round(posVector(entry)) 
    
    // Rank 2->6 rounding
    for entry in posVectorRank where posVectorRank(entry) = 2 to 6
        previousInteger = posVector(entry-1)
        if round(posVector(entry-1)) equals previousInteger
            posVector(entry) = round(posVector(entry))+1
        else
            posVector(entry) = round(posVector(entry))
    

    This would result in the final posVectorInt as

    posVectorInt(particle i) = {1, 0, 2, 6, 4, 3}.
    

    Note, however, that it's probably better to build a more sophisticated "rank -> integer" function that takes into account e.g. swarm best or particle best values w.r.t. the objective function.

    If you're using this method to find the optimal solution to some optimization problem with mixed continuous and integer valued (decision) variables, note that such problems are non-convex. Going, by rounding, from a "good" continuously relaxed variable vector to one that is (integer) feasible in the non-relaxed problem doesn't necessarily yield a "good" solution in the latter. Hence, if you decide to use PSO in such context, the "rank -> integer" method should probably contain some clever heuristics, constructed with the actual problem to be solved in mind. This, in itself, is---in my experience---an unusual approach for using PSO, as PSO can generally be considered a "brute-force" method of solving nonlinear/nonconvex optimisation problems with continuous variables.