I'm writing a code to minimize a function and I'm having problems storing the new move.

import math
import random

#minimze the function:
def f(x):
	return math.pow(x,2) + math.sin(10*x)

x_list=[]
energy_list=[]
g=2 #starting position
def move(): #Generate a random move
	random.uniform(-0.5,0.5) 
	

def energy():
	h=g+move() #generate random move
	E = f(g)-f(h) #energy difference
	if E>0:
		x_list.append(h) #store position and energy
		energy_list.append(f(h))
		g==H #set g equal to the new move
	if E<0: 
		R=random.uniform(0,1)
		if R<math.exp(-E/1.5): #get out of the local minimum
			h=R+g
			x_list.append(h)
			energy_list.append(f(h))
		else:
			x_list.pop()
			energy_list.pop()
N=50

for i in range(N):
	energy()


print g
print x_list
print energy_list
print min(energy_list)

I want to store the value of g with the new move. My code keeps starting from the original position (which is 2). Does anyone know how to do this?

Dani AI

Generated

The quick wins from get you past the immediate syntax/scope traps. For a more robust approach, avoid mutating a module-level g inside the step function. Treat the current position as a local value, return the new position when accepted, and keep a history list you never pop blindly. The snippet below shows a small, clear refactor that implements a standard simulated-annealing step and records accepted states.

import random
import math

def propose(x, step=0.5):
    return x + random.uniform(-step, step)

def accept(delta_e, T):
    return delta_e <= 0 or random.random() < math.exp(-delta_e / T)

def simulated_anneal(x0, f, steps=100, T0=1.0, step=0.5):
    x = x0
    history = [(x, f(x))]
    T = T0
    for i in range(steps):
        x_new = propose(x, step)
        delta = f(x_new) - f(x)
        if accept(delta, T):
            x = x_new
            history.append((x, f(x)))
        T *= 0.99
    return x, history

# example: best_x, hist = simulated_anneal(2.0, f, steps=50, T0=1.5)

Practical notes: always include the initial state in history, avoid pop() as a control flow mechanism (it can underflow and hides logic), and be explicit about the sign of delta (I use delta = f(new) - f(current) here). For reproducible runs, seed the RNG (random.seed(...)) — see the Python random docs (https://docs.python.org/3/library/random.html). If a production-ready global optimizer is desired, consider scipy.optimize.basinhopping for a tested implementation (https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.basinhopping.html).

Tweak the temperature schedule, step size, and number of iterations while printing acceptance statistics for debugging. This pattern should make the state transitions predictable and easier to inspect than relying on globals.

Recommended Answers

All 2 Replies

I'm writing a code to minimize a function and I'm having problems storing the new move.

import math
import random

#minimze the function:
def f(x):
	return math.pow(x,2) + math.sin(10*x)

x_list=[]
energy_list=[]
g=2 #starting position
def move(): #Generate a random move
	random.uniform(-0.5,0.5) 
	

def energy():
	h=g+move() #generate random move
	E = f(g)-f(h) #energy difference
	if E>0:
		x_list.append(h) #store position and energy
		energy_list.append(f(h))
		g==H #set g equal to the new move
	if E<0: 
		R=random.uniform(0,1)
		if R<math.exp(-E/1.5): #get out of the local minimum
			h=R+g
			x_list.append(h)
			energy_list.append(f(h))
		else:
			x_list.pop()
			energy_list.pop()
N=50

for i in range(N):
	energy()


print g
print x_list
print energy_list
print min(energy_list)

I want to store the value of g with the new move. My code keeps starting from the original position (which is 2). Does anyone know how to do this?

There was a missing 'return' in your code as well as a mistyped 'g==H' instead of 'g = h'. Also there was a more subtle error: since energy() contains a statement 'g = ...', the interpreter thinks that 'g' is a local variable in energy(), and it complains because 'g' was not initialized before 'h = g + move()'. A solution is to add a global statement at the beginning of energy(). A better solution would be to pass g as a parameter of the function. Here is your corrected code

import math
import random

#minimze the function:
def f(x):
	return math.pow(x,2) + math.sin(10*x)

x_list=[]
energy_list=[]
g=2 #starting position
def move(): #Generate a random move
	return random.uniform(-0.5,0.5) # <---- Added missing return statement

def energy():
	global g # <---- Added global declaration
	h=g+move() #generate random move
	E = f(g)-f(h) #energy difference
	if E>0:
		x_list.append(h) #store position and energy
		energy_list.append(f(h))
		g = h #set g equal to the new move # <---- This was mistyped
	if E<0: 
		R=random.uniform(0,1)
		if R<math.exp(-E/1.5): #get out of the local minimum
			h=R+g
			x_list.append(h)
			energy_list.append(f(h))
		else:
			x_list.pop()
			energy_list.pop()
N=50

for i in range(N):
	energy()


print g
print x_list
print energy_list
print min(energy_list)

Also, your code is indented with tab characters, so please configure your editor to indent python code with 4 spaces instead of a tab character.
I added a picture of your function :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.