Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Annotate normal_form_game.py #576

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Annotate normal_form_game.py #576

wants to merge 1 commit into from

Conversation

rht
Copy link
Contributor

@rht rht commented Apr 16, 2021

  • np.ndarray is a catch-all type for all ndarrays regardless of its dtype, and so, is unfortunately less specific than the docstring that specifies ndarray.
  • I'm unsure of the type of action_profile since the functions using it are not documented.
  • I found this bug: normal_form_game.py:921: error: Missing return statement in . There is a case where the function returns None instead of int when the if condition is never satisfied.

@pep8speaks
Copy link

Hello @rht! Thanks for opening this PR. We checked the lines you've touched for PEP 8 issues, and found:

Line 204:80: E501 line too long (82 > 79 characters)
Line 259:80: E501 line too long (92 > 79 characters)
Line 525:9: E125 continuation line with same indent as next logical line
Line 525:80: E501 line too long (86 > 79 characters)
Line 732:80: E501 line too long (94 > 79 characters)
Line 759:80: E501 line too long (86 > 79 characters)
Line 817:80: E501 line too long (90 > 79 characters)
Line 922:80: E501 line too long (83 > 79 characters)

@rht
Copy link
Contributor Author

rht commented Apr 16, 2021

Will fix the line too long issues later.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.003%) to 94.338% when pulling b2a8f98 on rht:master into 6ffbe57 on QuantEcon:master.

@rht
Copy link
Contributor Author

rht commented Apr 16, 2021

There is a case where the function returns None instead of int when the if condition is never satisfied.

There is never such case, from the way payoff_max is specified, but Mypy isn't aware of this. Just ignore the error?

@mmcky
Copy link
Contributor

mmcky commented Apr 16, 2021

Just ignore the error?

In Mypy is there a way to add an ignore such as # noqa for coveralls?

@oyamad
Copy link
Member

oyamad commented Apr 16, 2021

There is a case where the function returns None instead of int when the if condition is never satisfied.

Yes, it happens when tol < 0. (tol is supposed to be nonnegative, but it is just implicit.)

There are two options:

  1. Just return -1 when the if condition is never satisfied (which happens if and only if tol < 0).
  2. Let tol = 0 if tol < 0.

Maybe option 1?

@rht
Copy link
Contributor Author

rht commented Apr 16, 2021

There is a type: ignore for a single line, but the error appears exactly at the def best_response_2p(...) line. If this line is disabled, the entire function signature's type checking will also be disabled.

@rht
Copy link
Contributor Author

rht commented Apr 16, 2021

Just return -1 when the if condition is never satisfied (which happens if and only if tol < 0).

Maybe it is safer to tell the user there is a problem instead of -1? I tried raising an Exception at the end and Mypy no longer complains about missing a return. What should the exception message be?

@@ -233,7 +240,7 @@ def delete_action(self, action, player_idx=0):
payoff_array_new = np.delete(self.payoff_array, action, player_idx)
return Player(payoff_array_new)

def payoff_vector(self, opponents_actions):
def payoff_vector(self, opponents_actions: npt.ArrayLike) -> np.ndarray:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opponents_actions should have been IntOrArray, which is Union[int, npt.ArrayLike].
But doing so will cause problem in

reduce_last_player(payoff_vector, opponents_actions[i])
. A Union[int, ...] type generally can't be indexed. Alternative solution to my current version is to use cast() before the indexing to cast opponents_actions into an indexable.

Note that int is also part of npt.ArrayLike, since np.array(1) works.

@mmcky
Copy link
Contributor

mmcky commented Apr 30, 2021

Just return -1 when the if condition is never satisfied (which happens if and only if tol < 0).

Maybe it is safer to tell the user there is a problem instead of -1? I tried raising an Exception at the end and Mypy no longer complains about missing a return. What should the exception message be?

thanks @rht sorry for my slow response.

tol is supposed to be nonnegative, but it is just implicit

@oyamad should we add an exception if tol is negative instead and then the return is bounded.

@oyamad
Copy link
Member

oyamad commented Apr 30, 2021

should we add an exception if tol is negative instead

Actually, this function best_response_2p is for internal use. Negative tol should be handled by the outer function that calls best_response_2p. Let's just return some int, say -1, and write in the docstring, something like "Return -1 if there is no best response action, which occurs when tol < 0".

@oyamad
Copy link
Member

oyamad commented Apr 30, 2021

I'm unsure of the type of action_profile since the functions using it are not documented.

  • action_profile in __getitem__ and __setitem__ is int if N=1 and array_like if N>=2.
  • action_profile in is_nash is array_like.

So your annotations are correct.

@rht
Copy link
Contributor Author

rht commented May 1, 2021

should we add an exception if tol is negative instead

Actually, this function best_response_2p is for internal use. Negative tol should be handled by the outer function that calls best_response_2p. Let's just return some int, say -1, and write in the docstring, something like "Return -1 if there is no best response action, which occurs when tol < 0".

best_response_2p is currently exported as an external function (

from .normal_form_game import pure2mixed, best_response_2p
) and is not used internally anywhere in the module.

@mmcky
Copy link
Contributor

mmcky commented Apr 5, 2022

@oyamad are you happy with these annotations?

@oyamad oyamad self-assigned this Apr 5, 2022
@rht
Copy link
Contributor Author

rht commented Apr 5, 2022

I think it is safe to replace all of IntOrArrayT with npt.ArrayLike? The code selection part that checks whether actions is a scalar or array happens in

if isinstance(action, numbers.Integral): # pure action
return payoff_array.take(action, axis=-1)
else: # mixed action
return payoff_array.dot(action)
.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants