Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Type Hints, Fix Mypy Errors, and Refactor Code in AEPsych Directory #413

Closed
wants to merge 15 commits into from

Conversation

yalsaffar
Copy link
Contributor

Description:

This PR adds type hints, resolves Mypy errors, and refactors code across multiple modules in AEPsych. Key changes include type hint additions, tensor conversions for compatibility, and improved error handling. This is the first step towards resolving issue #366.

Changes by Directory:

1. acquisitions/:

  • Added type hints across files.
  • Refactored construct_inputs_global_lookahead to use tensors for lb and ub instead of lists.

2. benchmark/:

  • Added type hints.
  • In problem.py, updated LSEProblemWithEdgeLogging.evaluate to use tensors for metrics["prop_edge_sampling_err"].

3. database/, generators/, kernels/, likelihoods/:

  • Added type hints throughout.
  • kernels/pairwisekernel.py: Updated PairwiseKernel.forward to avoid assigning tensor d as both an integer and tensor, ensuring Mypy compatibility.

4. models/:

  • Added type hints.
  • gp_classification.py: Added assertions (inducing_points is not None) in the constructor and _reset_variational_strategy.
  • semi_p.py: Added tensor conversion for X in SemiParametricGPModel.posterior to avoid Mypy errors.

5. Root-Level AEPsych Files:

  • Added type hints throughout.
  • strategy.py: Added assertions to check for None in self.model, self.x, and self.y to prevent errors.
  • utils.py: Wrapped all occurrences of parname with str() for compatibility with the Config class.
  • plotting.py:
    • Refactored plot_strat_3d to improve handling of contour_levels:
      • Introduced detailed checks for contour_levels_list to ensure it is Sized (e.g., list or array).
      • Improved type handling for slice_vals, ensuring proper error messages and type checking.
      • Added error handling for cases where the model is None, raising a RuntimeError instead of silently failing.
    • Updated plot_slice to ensure better control over contour_levels:
      • Enforced type checking on contour_levels and ensured non-None values are provided, with clearer error messages.
      • Refactored the function to raise an explicit error (ValueError) if contour_levels is incorrectly set to None.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 22, 2024
Copy link
Contributor

@JasonKChow JasonKChow left a comment

Choose a reason for hiding this comment

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

Some typehints are missing:
from_config all over are missing return hints
lookahead_type
init missing return None -- Semi_p.py file
problem.py Problem class properties missing return typehints.
problem.py has a TODO comment in sample_y method, maybe make a small PR to fix this if possible.
config.py Config missing type hints in methods (e.g., get_section())
db.py Database missing type hints
Likelihood semi_p.py file "expected_log_prob" missing type hints.

Shouldn't everything be using Tensors now?

aepsych/acquisition/lookahead.py Show resolved Hide resolved
aepsych/acquisition/lse.py Show resolved Hide resolved
aepsych/acquisition/mc_posterior_variance.py Show resolved Hide resolved
aepsych/acquisition/mutual_information.py Show resolved Hide resolved
aepsych/benchmark/problem.py Show resolved Hide resolved
aepsych/utils.py Show resolved Hide resolved
aepsych/utils.py Show resolved Hide resolved
aepsych/utils.py Outdated Show resolved Hide resolved
aepsych/utils.py Show resolved Hide resolved
aepsych/utils.py Show resolved Hide resolved
@yalsaffar
Copy link
Contributor Author

I’ve gone ahead and added return type hints for the from_config method throughout the codebase. Along the way, I also fixed the type hints for lookahead_type, and made sure all the __init__ methods that were missing None return types are now sorted out.

The TODO comment in Problem.py is still on the radar, but I’ll tackle that in a follow-up PR after this one. I also worked on config.py by fixing the missing type hints in methods like get_section(), and I cleaned up some issues in db.py related to the Database.

For semi_p.py, I added the missing type hints for expected_log_prob, even though it’s not currently being used. Most of the specific changes have already been resolved, but a few are still up for discussion. As soon as I get more feedback, I’ll add those as well.

Lastly, most parts of the code where tensors are needed for GPU support have been converted. The one exception is in the add_data method, which still accepts both tensors and np.ndarrays. This is because, as discussed in #403, it's the first point where data is accepted, and from there, everything is processed as tensors.

Copy link
Contributor

@JasonKChow JasonKChow left a comment

Choose a reason for hiding this comment

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

Many comments.

In general: avoid adding extra asserts to fix mypy problems, instead work out how to make the type hints align. Basically, no actual functional code should be written for most mypy problems, just modifying hints.

aepsych/utils.py Show resolved Hide resolved
aepsych/database/tables.py Show resolved Hide resolved
@@ -61,7 +61,7 @@ def __init__(
self.samps = samps
self.stimuli_per_trial = stimuli_per_trial

def _instantiate_acquisition_fn(self, model: ModelProtocol):
def _instantiate_acquisition_fn(self, model: ModelProtocol) -> AnalyticExpectedUtilityOfBestOption:
Copy link
Contributor

Choose a reason for hiding this comment

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

Double check again. Doesn't appear changed.

aepsych/generators/monotonic_rejection_generator.py Outdated Show resolved Hide resolved
inducing_points = select_inducing_points(
inducing_size=self.inducing_size,
covar_module=self.covar_module,
X=self.train_inputs[0],
bounds=self.bounds,
method=self.inducing_point_method,
)
assert inducing_points is not None, "Inducing points cannot be None"
Copy link
Contributor

Choose a reason for hiding this comment

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

These are presumably for mypy errors, I don't like adding asserts to solve mypy errors, see if you can figure out a different way.

@@ -57,7 +58,7 @@ def select_inducing_points(
X: Optional[torch.Tensor] = None,
bounds: Optional[Union[torch.Tensor, np.ndarray]] = None,
method: str = "auto",
):
) -> Optional[torch.Tensor]:
Copy link
Contributor

Choose a reason for hiding this comment

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

Should always be tensors (also this Optional might be the cause of other problems above that require Asserts).

contour_levels_list: List[float] = []

if contour_levels is True:
contour_levels_list = [0.75]
Copy link
Contributor

Choose a reason for hiding this comment

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

It's a very complex argument it seems. It has to allow bool to default it to all ints. Double check if this is absolutely necessary.

self.is_finished = True

@property
def finished(self):
def finished(self) -> Union[bool,torch.Tensor, None]:
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be strictly bool, why not?

if self.can_fit:
if self.keep_most_recent is not None:
try:
assert self.model is not None, "a model is needed here!"
Copy link
Contributor

Choose a reason for hiding this comment

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

Assert probably due to above Optional on can_fit. Wherever assert ends up being weirdly needed, it's likely because of an odd typing somewhere else that should be fixed instead.

Copy link
Contributor

Choose a reason for hiding this comment

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

Add type hints for arguments, then try again, if not ask again.

@facebook-github-bot
Copy link
Contributor

@JasonKChow has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

aepsych/acquisition/lookahead.py Show resolved Hide resolved
aepsych/acquisition/lookahead.py Outdated Show resolved Hide resolved
aepsych/benchmark/problem.py Outdated Show resolved Hide resolved
aepsych/benchmark/problem.py Show resolved Hide resolved
aepsych/kernels/pairwisekernel.py Outdated Show resolved Hide resolved
aepsych/models/semi_p.py Outdated Show resolved Hide resolved
aepsych/strategy.py Outdated Show resolved Hide resolved
@facebook-github-bot
Copy link
Contributor

@JasonKChow has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@JasonKChow has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@JasonKChow merged this pull request in fba7f99.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants