How to pass shared variable in scipy differential evolution with worker > 2

Question:

I want to pass a shared variable in python scipy "differential_evolution" to keep track of experiment number. I can do this with worker=1 , but i am unable to keep track of experiment number with worker > 2.
Here is my code:

from scipy.optimize import differential_evolution

def objectiveFunction(x,experiment_no ):
    y=x[0]+x[1]
    # Keep track of experiment number
    experiment_no["exp"]=experiment_no["exp"]+1
    print("This is expriment no :"+ str(experiment_no["exp"]))
    return y

if __name__ == "__main__":
    minRanges=[1.2,10]
    maxRanges=[1.5,20]
    experiment_no={}
    experiment_no["exp"]=0
    try:
        bounds = list(zip(minRanges,maxRanges))
        
        result = differential_evolution(objectiveFunction,bounds, args=(experiment_no,),strategy="best1bin", workers=1,  maxiter=int("2"), updating="deferred", polish=False)        
   
        print('Global minimum [x]:')
        print(result.x)
        print('Function value at global minimum [f(x)]:')
        print(result.fun)
    except :
        exit( sys.exc_info()[:2])


with workers=1 my output is : 
This is expriment no :1
This is expriment no :2
This is expriment no :3
This is expriment no :4
This is expriment no :5
This is expriment no :6
....
but with workers=2 or 3 , my output is :
This is expriment no :1
This is expriment no :1
This is expriment no :11
This is expriment no :1
This is expriment no :1
This is expriment no :1


How can i achieve my below output with workers=2 ?
This is expriment no :1
This is expriment no :2
This is expriment no :3
This is expriment no :4
This is expriment no :5
This is expriment no :6
Asked By: First Python

||

Answers:

I’m not sure if it is the best way, but it is working through a thread-safe counter:

from scipy.optimize import differential_evolution
from multiprocessing import Process, RawValue, Lock


class Counter(object):
    def __init__(self, value=0):
        # RawValue because we don't need it to create a Lock:
        self.val = RawValue('i', value)
        self.lock = Lock()

    def increment(self):
        with self.lock:
            self.val.value += 1
            return self.val.value


class ExpermientInfo:
    no = Counter()

    def increment():
        return ExpermientInfo.no.increment()


def objectiveFunction(x):
    y = x[0]+x[1]
    # Keep track of experiment number
    no = ExpermientInfo.increment()
    print("This is expriment no :" + str(no))
    return y


if __name__ == "__main__":
    minRanges = [1.2, 10]
    maxRanges = [1.5, 20]
    try:
        bounds = list(zip(minRanges, maxRanges))
        counter = 0

        result = differential_evolution(objectiveFunction, bounds, args=(
        ), strategy="best1bin", workers=2,  maxiter=int("2"), updating="deferred", polish=False)

        print('Global minimum [x]:')
        print(result.x)
        print('Function value at global minimum [f(x)]:')
        print(result.fun)
    except:
        exit(sys.exc_info()[:2])
Answered By: Majid