Why Isn't 'Method=' Treated the Same as Any Other Method

Why isn't `method=` treated the same as any other method?

This is how assignment works; the return value is ignored, and the result of an assignment expression is always the right-hand value. This is a fundamental feature of Ruby's grammar. left-hand side = right-hand side will always evaluate to right-hand side, regardless of whether left hand side is a variable (x), a method (object.x), a constant (X) or any expression.

Source: Programming Languages | Ruby
IPA Ruby Standardization WG Draft, 11.4.2.2.5, Single method assignments


Consider chaining of assignments, x = y = 3.

For this to work correctly, the result of y = 3 must be 3, regardless of the actual value returned by the y= method. x = y = 3 is meant to read as y = 3; x = 3, not as y = 3; x = y which is what would be implied if the return value from y= was treated as the result of y = 3.

Or consider all the other places assignment can be used. Sometimes, instead of this...

obj.x = getExpensiveThing()
if obj.x
...

... we write this ...

if obj.x = getExpensiveThing()

This couldn't work if the result of obj.x = ... could be any arbitrary thing, but we know it will work because the result of obj.x = y is always y.

Update

A comment on the question states:

Interesting, I wasn't aware of this scenario. It seems that method= returns whatever input is given...

No, it's an important distinction to make. This has nothing to do with the return value of method assignment, and it definitely does not "return whatever input is given", it returns whatever you tell it to return.

The whole point is that the return value is ignored by the grammar of the language; assignment doesn't evaluate to the return value of the attr= method, but the return value still exists as evidenced by the question itself: Example.new.send(:my_attr=, 5) # => 15. This works because it is not assignment. You're side-stepping that part of the Ruby language.

Update again

To be clear: x and y in my examples shouldn't be interpreted as literal Ruby variables, they are place holders for any valid left-hand side of an assignment. x or y could be any expression: a, obj.a, CONSTANT_A, Something::a, @instance_a, it's all the same. The value of assignment is always the right-hand side.

Python class methods: when is self not needed

What is self?

In Python, every normal method is forced to accept a parameter commonly named self. This is an instance of class - an object. This is how Python methods interact with a class's state.

You are allowed to rename this parameter whatever you please. but it will always have the same value:

>>> class Class:
def method(foo): #
print(foo)


>>> cls = Class()
>>> cls.method()
<__main__.F object at 0x03E41D90>
>>>

But then why does my example work?

However, what you are probably confused about is how this code works differently:

>>> class Class:
def method(foo):
print(foo)

methods = {'method': method}

def __init__(self):
self.run = self.methods['method']


>>> cls = Class()
>>> cls.run(3)
3
>>>

This is because of the distinction between bound, and unbound methods in Python.

When we do this in __init__():

self.run = self.methods['method']

We are referring to the unbound method method. That means that our reference to method is not bound to any specific instance of Class, and thus, Python will not force method to accept an object instance. because it does not have one to give.

The above code would be the same as doing this:

>>> class Class:
def method(foo):
print(foo)


>>> Class.method(3)
3
>>>

In both examples, we are calling the method method of the class object Class , and not an instance of the Class object.

We can further see this distinction by examining the repr for a bound and unbound method:

>>> class Class:
def method(foo):
print(foo)


>>> Class.method
<function Class.method at 0x03E43D68>
>>> cls = Class()
>>> cls.method
<bound method Class.method of <__main__.Class object at 0x03BD2FB0>>
>>>

As you can see, in the first example when we do Class.method, Python shows:
<function Class.method at 0x03E43D68>. I've lied to you a little bit. When we have an unbound method of a class, Python treats them as plain functions. So method is simply a function that is not bound to any instance of `Class.

However in the second example, when we create an instance of Class, and then access the method object of it, we see printed: <bound method Class.method of <__main__.Class object at 0x03BD2FB0>>.

The key part to notice is bound method Class.method. That means method is **bound** to cls - a specfic an instance of Class.

General remarks

As @jonshapre mentioned, writing code like in your example leads to confusion (as proof by this question), and bugs. It would be a better idea if you simply defined nonLinearBipolarStep() outside of Activation, and reference that from inside of Activation.activation_functions:

def nonLinearBipolarStep(self,x,string=None):
if not string: return (-1 if x<0 else 1 )
else: return ('-' if x<0 else '1')

class Activation:

activation_functions = {
'bipolar': nonLinearBipolarStep,
}

...

I guess a more specific question would be: what should I pay attention to on that code in order to become evident that ag.run(x) would be a call to an unbound function?

If you'd still like to let nonLinearBipolarStep be unbound, then I recommend simply being carefully. If you think your method would make for the cleanest code then go for it, but make sure you know what you are doing and the behavior your code will have.

If you still wanted to make is clear to users of your class that ag.run() would be static, you could document it in a docstring somewhere, but that is something the user really shouldn't even have to be concerned with at all.

Why the value of the assignment is always the value of the parameter?

It's not uncommon to chain assignments together when you want to assign the same value to multiple variables. This is even more common in other languages.

@user_id = user.id = next_user_id

But what happens when you aren't thinking about that, and so the return value isn't the same as the input value?

class User
def id=(name)
@id = name
@modified = true
end

def modified?
@modified
end
end

This code will work totally fine until one day when you go drop it in an assignment chain like the above, when all of a sudden you'll get unexpected results.

So, the interpreter does some sort of voodoo and ensures that the RHS of the assignment is the return value, discarding the actual return value.

TypeError: method() takes 1 positional argument but 2 were given

In Python, this:

my_object.method("foo")

...is syntactic sugar, which the interpreter translates behind the scenes into:

MyClass.method(my_object, "foo")

...which, as you can see, does indeed have two arguments - it's just that the first one is implicit, from the point of view of the caller.

This is because most methods do some work with the object they're called on, so there needs to be some way for that object to be referred to inside the method. By convention, this first argument is called self inside the method definition:

class MyNewClass:

def method(self, arg):
print(self)
print(arg)

If you call method("foo") on an instance of MyNewClass, it works as expected:

>>> my_new_object = MyNewClass()
>>> my_new_object.method("foo")
<__main__.MyNewClass object at 0x29045d0>
foo

Occasionally (but not often), you really don't care about the object that your method is bound to, and in that circumstance, you can decorate the method with the builtin staticmethod() function to say so:

class MyOtherClass:

@staticmethod
def method(arg):
print(arg)

...in which case you don't need to add a self argument to the method definition, and it still works:

>>> my_other_object = MyOtherClass()
>>> my_other_object.method("foo")
foo

Treatment of constraints in SLSQP optimization with openMDAO

Based on your provided test case, the problem here is that your have a really poorly scaled objective and constraint (you also have some very strange coding choices ... which I modified).

Running the OpenMDAO scaling report shows that your objective and constraint values are both around 1e6 in magnitude:

scaling report

This is quite large, and is the source of your problems. A (very rough) rule of thumb is that your objectives and constraints should be around order 1. Thats not hard and fast rule, but is generally a good starting point. Sometimes other scaling will work better, if you have very very larger or small derivatives ... but there are parts of SQP methods that are sensitive to the scaling of objective and constraint values directly. So trying to keep them roughly in the range of 1 is a good idea.

Adding ref=1e6 to both objective and constraints gave enough resolution for the numerical methods to converge the problem:

            Current function value: [0.229372]
Iterations: 8
Function evaluations: 8
Gradient evaluations: 8
Optimization Complete
-----------------------------------
minimum found at
20.00006826587515
[3.61138704 3. 3.61138704]
constraint
197.20821903413162
minimum objective
229371.99547899762

Here is the code I modified (including removing the extra class definitions inside your group that didn't seem to be doing anything):

import numpy as np
import openmdao.api as om


class d1(om.ExplicitComponent):

def setup(self):

# Global design variables
self.add_input('r', val= [3,3,3])
self.add_input('T', val= 20)

# Coupling output
self.add_output('M', val=0)
self.add_output('cost', val=0)

def setup_partials(self):
# Finite difference all partials.
self.declare_partials('*', '*', method='cs')

def compute(self, inputs, outputs):
# define inputs
r = inputs['r']
T = inputs['T'][0]

cost = 174.42 * T * (r[0]**2 + 2*r[1]**2 + r[2]**2 + r[0]*r[1] + r[1]*r[2])

M = 456.19 * T * (r[0]**2 + 2*r[1]**2 + r[2]**2 + r[0]*r[1] + r[1]*r[2]) - 599718

outputs['M'] = M
outputs['cost'] = cost


class MDA(om.Group):

def setup(self):

self.add_subsystem('d1', d1(), promotes_inputs=['r','T'],
promotes_outputs=['M','cost'])

# self.add_subsystem('con_cmp', self.ConCmp(), promotes_inputs=['M'],
# promotes_outputs=['con'])

# self.add_subsystem('obj_cmp', self.ObjCmp(), promotes_inputs=['cost'],
# promotes_outputs=['obj'])


# Build the model
prob = om.Problem(model=MDA())
model = prob.model

model.add_design_var('r', lower= [3,3,3], upper= [10,10,10])
model.add_design_var('T', lower= 20, upper= 220)
model.add_objective('cost', ref=1e6)
model.add_constraint('M', lower=0, ref=1e6)

# Setup the optimization
prob.driver = om.ScipyOptimizeDriver(optimizer='SLSQP', tol=1e-3, disp=True)

prob.setup()
prob.set_solver_print(level=0)

prob.set_val('r', 7.65)
prob.run_driver()

# Printout
print('minimum found at')
print(prob.get_val('T')[0])
print(prob.get_val('r'))

print('constraint')
print(prob.get_val('M')[0])

print('minimum objective')
print(prob.get_val('cost')[0])

What's the difference between a method and a function?

A function is a piece of code that is called by name. It can be passed data to operate on (i.e. the parameters) and can optionally return data (the return value). All data that is passed to a function is explicitly passed.

A method is a piece of code that is called by a name that is associated with an object. In most respects it is identical to a function except for two key differences:

  1. A method is implicitly passed the object on which it was called.
  2. A method is able to operate on data that is contained within the class (remembering that an object is an instance of a class - the class is the definition, the object is an instance of that data).

(this is a simplified explanation, ignoring issues of scope etc.)

[]= method always returns a value, even if I override

You cannot override the return value of = or []=. Or rather, you can return whatever you want, but it has no affect on the calling code.

The semantics of a = b[3] = c is not this...

b[3] = c
a = [b]3

It is this:

b[3] = c
a = c

Which equals operator (== vs ===) should be used in JavaScript comparisons?

The strict equality operator (===) behaves identically to the abstract equality operator (==) except no type conversion is done, and the types must be the same to be considered equal.

Reference: Javascript Tutorial: Comparison Operators

The == operator will compare for equality after doing any necessary type conversions. The === operator will not do the conversion, so if two values are not the same type === will simply return false. Both are equally quick.

To quote Douglas Crockford's excellent JavaScript: The Good Parts,

JavaScript has two sets of equality operators: === and !==, and their evil twins == and !=. The good ones work the way you would expect. If the two operands are of the same type and have the same value, then === produces true and !== produces false. The evil twins do the right thing when the operands are of the same type, but if they are of different types, they attempt to coerce the values. the rules by which they do that are complicated and unmemorable. These are some of the interesting cases:

'' == '0'           // false
0 == '' // true
0 == '0' // true

false == 'false' // false
false == '0' // true

false == undefined // false
false == null // false
null == undefined // true

' \t\r\n ' == 0 // true

Equality Comparison Table

The lack of transitivity is alarming. My advice is to never use the evil twins. Instead, always use === and !==. All of the comparisons just shown produce false with the === operator.


Update:

A good point was brought up by @Casebash in the comments and in @Phillipe Laybaert's answer concerning objects. For objects, == and === act consistently with one another (except in a special case).

var a = [1,2,3];
var b = [1,2,3];

var c = { x: 1, y: 2 };
var d = { x: 1, y: 2 };

var e = "text";
var f = "te" + "xt";

a == b // false
a === b // false

c == d // false
c === d // false

e == f // true
e === f // true

The special case is when you compare a primitive with an object that evaluates to the same primitive, due to its toString or valueOf method. For example, consider the comparison of a string primitive with a string object created using the String constructor.

"abc" == new String("abc")    // true
"abc" === new String("abc") // false

Here the == operator is checking the values of the two objects and returning true, but the === is seeing that they're not the same type and returning false. Which one is correct? That really depends on what you're trying to compare. My advice is to bypass the question entirely and just don't use the String constructor to create string objects from string literals.

Reference

http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3

Does two generics method at the same call can cause a compile error when trying to use them?

What you have to understand is called Erasure of Generic Methods

It means, the method's type parameter is converted to Object if it's unbound

or

it's first bound class when it's bound.

Bound means, -staying at your example- you have declared a relation of the type parameter T to another class, like you did:

// 1. method  
public <T extends Dog> String helpMethod(T dog)
// 2. method
public <T extends Animal> String helpMethod(T animal)

T is bounded to Dog in the 1. method, and bounded to Animal in the 2. method.

So, when it comes to compiling, Java changes the T into Dog in the 1. method, and to Animal in the 2. method.

There is no ambiguity here, they are two different methods.

However, if you would declare a 3. method:

// 3. method
public <T> String helpMethod(T dog)

Then the T is unbound, you haven't declared a relation between T and another class, therefore when it comes to compiling, Java changes the T into Object.

Now, if you would try to declare a 4. method:

// 4. method
public String helpMethod(Object dog)

There would be a compilation error, as the 3. method during type erasure would have the exact same method signature as your 4. method.

The compiler cannot decide which one you want to call, and throws an error.

With the above in mind, the short answer is:

In you code, you are using two different methods, there is no ambiguity, so no error occurs.

If you want to see that compilation error, you should declare another generic method which signature after compiling would be the same as an existing generic/non-generic method in your class.



Related Topics



Leave a reply



Submit