0

Consider a black box function, f, which inputs x and return a real number, a.

def foo(x): ... return a

We know that f is a deterministic function of x. Suppose

x = []
for i in range(2):
    x.append({'type': 'eq', 'fun': lambda x: x[i] + x[3+i] - 1000})

and

y = [{'type': 'eq', 'fun': lambda x: x[0] + x[3+0] - 1000},
       {'type': 'eq', 'fun': lambda x: x[1] + x[3+1] - 1000}
       ]

I get that foo(x) != foo(y), which implies that x is not the same as y.

How is it possible that x is not the same as y? What are the differences between x and y?

Here is a verifiable and complete example:

import pandas as pd
import numpy as np
from scipy.optimize import minimize, Bounds

X0 = [0,0,0,0]

x = []
for i in range(2):
    x.append({'type': 'eq', 'fun': lambda x: x[i] + x[2+i] - 1000})

y = [{'type': 'eq', 'fun': lambda x: x[0] + x[2] - 1000},
       {'type': 'eq', 'fun': lambda x: x[1] + x[3] - 1000}
       ]

def f(a):
    return a[0] + a[1] + a[2] + a[3]


print(minimize(f, X0, constraints=x,
               bounds = bounds, options={'disp': False} ).x)
print(minimize(f, X0, constraints=y,
               bounds = bounds, options={'disp': False} ).x)

This prints:

[724.07734394 500. 0. 500. ]

[500. 500. 500. 500.]

Actually, y gives the correct result. Why is x giving an incorrect result?

Answering my own question:

Do this:

import pandas as pd
import numpy as np
from scipy.optimize import minimize, Bounds

X0 = [0,0,0,0]

x = []
for i in range(2):
    x.append({'type': 'eq', 'fun': lambda a, i=i: a[i] + a[split+i] - 1000})

y = [{'type': 'eq', 'fun': lambda x: x[0] + x[2] - 1000},
       {'type': 'eq', 'fun': lambda x: x[1] + x[3] - 1000}
       ]

def f(a):
    return a[0] + a[1] + a[2] + a[3]


print(minimize(f, X0, constraints=x,
               bounds = bounds, options={'disp': False} ).x)
print(minimize(f, X0, constraints=y,
               bounds = bounds, options={'disp': False} ).x)
John Doe
  • 185
  • 1
  • 8
  • 2
    Function objects are compared using *identity* – juanpa.arrivillaga Dec 25 '18 at 00:41
  • @juanpa.arrivillaga What is meant by identity? – John Doe Dec 25 '18 at 00:44
  • By object identity. Each function you create, even if it is exactly the same, are different function objects. – juanpa.arrivillaga Dec 25 '18 at 00:45
  • Identity might be part of it. However, also if foo() is truly a black box function you know nothing about, it might have side effects you don't know about so that every call returns a different value even if the inputs are the same . . . – Frank Merrow Dec 25 '18 at 00:50
  • @juanpa.arrivillaga Besides the identity, are there any other differences between x and y? The function, f, probably doesn't consider the identity of the function. – John Doe Dec 25 '18 at 00:50
  • @FrankMerrow It's not really a black box. I just said that to make my question cleaer. I tested that f is constant for every x. So your claim that f is non-deterministic is not true. – John Doe Dec 25 '18 at 00:51
  • 1
    You need to provide a [mcve] – juanpa.arrivillaga Dec 25 '18 at 00:53
  • So, wrap this all in a small python program and print out everything using pprint or equal. Also, print out both function return values to see where they differ. I did this an can tell you that x and y are equal except for the lamda pointers . . . I'll leave it to you to make sure they are equal at that level too. – Frank Merrow Dec 25 '18 at 01:06
  • @FrankMerrow Done. See question now. – John Doe Dec 25 '18 at 01:11
  • @juanpa.arrivillaga Done. See question now. – John Doe Dec 25 '18 at 01:11
  • @CharlesDuffy True. See the example I posted. Could you tell me why the outputs differ? I result I would like to see is with y as an input. – John Doe Dec 25 '18 at 01:15
  • 1
    Ahh, that edit helps, though it's still fairly far from satisfying the "minimal" part of the [mcve] definition. Why do you need `minimize()`, or even the scipy module at all, as part of your reproducer? I'd be surprised if the underlying issue couldn't be reproduced in 6 lines max -- and pulling out a major dependency will mean more people can reproduce the issue and test proposed solutions. – Charles Duffy Dec 25 '18 at 01:16
  • @CharlesDuffy I've tried to reproduce without minimize but cannot. My apologies. – John Doe Dec 25 '18 at 01:19
  • @CharlesDuffy you could pip install scipy – John Doe Dec 25 '18 at 01:20
  • In case it's not clear from the linked duplicate, the problem here is that in: `lambda x: x[i] + x[3+i] - 1000` you have use a nonlocal `i`. That `i` is the one in the `for` loop. When the for loop completes, `i` is 1, so both x[0] and x[1] contain functions that use `arg[1]`, never `arg[0]`. – torek Dec 25 '18 at 01:39
  • @torek thanks, how would I go about fixing it? – John Doe Dec 25 '18 at 01:45
  • There are several methods shown in the linked duplicate. The least confusing is to define an intermediate function, rather than the nested lambdas. (The common Python solution is the two-argument lambda with defaulted parameter.) – torek Dec 25 '18 at 01:50
  • @torek Great catch, I should have seen that . . . well done. – Frank Merrow Dec 27 '18 at 23:29

0 Answers0