Problem with scoping in iteration of function evaluation

I have a function (call it feval) that takes a function guess as an argument, and outputs a new function. I want to iterate on this function until a convergence criterion is met. I am struggling to update the guessed function with Julia’s scoping rules, because when I do something like “old_guess = new_guess”, it binds the old guess to the new guess, which in the next function evaluation makes the two functions equal on the domain I’m interested in, resulting in detected convergence where there isn’t actually convergence. How would I fix the below code block so that the old guess doesn’t isn’t bound to the new guess?

old_guess = guess_init
while cDiff > tol
    new_guess = feval(old_guess)
    cDiff = distance_compute(new_guess, old_guess)
    old_guess = new_guess

I’m afraid there isn’t enough information here to solve your problem - the assignment old_guess = new_guess simply makes old_guess refer to the same object new_guess refers to, which isn’t related to scoping at all.

Perhaps you can expand on what feval does exactly, or provide a minimal (non-)working example we can run to show the issue?


Hello, I don’t think there is an issue with assigning the function to the old_guess variable.

The behavior you are reporting (both new_guess and old_guess returning the same value) can occur for several reasons (I cannot say much without you giving more details about feval). However - since you are returning functions from feval - please take a look at the potential closures: if your returned functions (new_guess) are mutating closures inside the feval - the next call of old_guess will also use the updated closure value.

Here is a working example with some dumb placeholders - but it does the job: you can test it and see the assignment working properly for old_guess = new_guess (e.g., your output being equal for the two functions is not caused by an assignment issue):

function bigfun()	
	function makefeval() 		
		counter = 100				
		function (_, name)
			@info "making new $name function"		
			() -> begin 			
				counter = counter - 1
				@info "I am returning $counter for $name"
				counter  < 1 ? 0 : counter
	feval = makefeval()
	distance_compute(ng, of) = ng() - og()
	# init
	old_guess = begin
		@info "will return: 1"
		() -> 1
	cDiff = 1
	tol = 0
	runs = 1
	while cDiff > tol     
		new_guess = feval(old_guess, "f$runs")
		cDiff = distance_compute(new_guess, old_guess)
		@info "cDiff: $cDiff"	    
		old_guess = new_guess
		runs = runs + 1		

Calling the above outputs the following:

will return: 1
making new f1 function
I am returning 99 for f1
cDiff: 98
making new f2 function
I am returning 98 for f2
I am returning 97 for f1
cDiff: 1
making new f3 function
I am returning 96 for f3
I am returning 95 for f2
cDiff: 1
... and so on until the `counter` reaches 0 - when cDiff will be 0 and the `while` loop will exit.

Feel free to share more context if this doesn’t answer your issue.

1 Like

As others have said, there isn’t enough info here to definitively answer your question.

My initial guess was that old_guess and new_guess are arrays or some other mutable type. But as you’ve written it, this shouldn’t be a problem unless feval(old_guess) modifies the input and returns it (i.e., old_guess is modified inside feval and then returned so that new_guess is bound to it). If this is the case, you could write new_guess = feval(copy(old_guess)) so that the original old_guess is not modified, but rather copied to a new array which is then modified and bound to new_guess. There are cleaner and more efficient ways of making this change, but we’ll start with correctness since I’m not even sure this is your problem. Alternatively, you could make sure that feval does not modify its input.

But this may be entirely unrelated to your problem. As others have said, without a better sense of what guess_init and feval are, it’s difficult to know what the issue is.

I didn’t read the original post closely enough.

I think the post’s author was clear that both new_guess and old_guess are functions (from …a function (call it feval) that takes a function guess as an argument, and outputs a new function).

It seems that he is doing some function search.

Please see my above attempt to fill in the gaps and produce a working example (assuming the …a function (call it feval) that takes a function guess as an argument, and outputs a new function thing).