Skip to content
This repository has been archived by the owner on Sep 20, 2022. It is now read-only.

ZQS-721 Implement initial PoC of cost function logger #417

Merged
merged 6 commits into from
Sep 2, 2021

Conversation

dexter2206
Copy link
Contributor

This PR implements a versatile framework for augmenting cost functions and includes a function logger implemented in this framework.

API description:

  • Wrappers for cost functions (like logger, and others in the future) are called augmentations.
  • Augmentations are done via augment_cost_function, which accepts a function to augment, and optional lists of augmentations for augmenting the function and its gradient. For instance
# Augments only cost function, gradient is left unchanged
augmented_func = augment_cost_function(func, [function_logger(level=level)])

# Augments both cost function and gradient, in different ways
augmented_func = augment_cost_function(
     func,
     cost_function_augmentations=[function_logger(level=logging.INFO)],
     gradient_augmentations=[function_logger(level=logging.DEBUG)]
)
  • Augmentations preserve attributes of cost functions, e.g. if in the above example func has number_of_layers attribute then augmented_func has it as well. Accessing such attributes (both querying and setting) are forwarded to the underlying function.
  • Implementers of augmentations don't have to handle this forwarding themselves, the internal machinery of augment_cost_function already ensures that.
  • If more than one augmentation is provided, they are applied in left-to-right order.

Main architectural decisions:

  • Augmentations are just higher-order functions transforming functions into functions.
  • A specific type of augmentation, called ConditionalSideEffect is implemented as an ABC for convenience. This specific type of augmentations passes through arguments to the wrapped function and propagates the return value, while triggering some side effect (e.g. logging) when the predicate is met. The predicates are the same as save_conditions in our history recorders (which is why they are reused in the code proposed in this PR).
  • FunctionLogger is implemented as a subclass of ConditionalSideEffect.
  • ConditionalSideEffects need to be wrapped into a higher order function. In case of FunctionLogger it is function_logger.
  • Attribute forwarding prioritizes augmentation attributes. For instance, if both a function and its augmentation have bar attribute then accessing bar of the augmented function accesses augmentation's attribute (see tests for examples of this behavior)

Some questions that are still open:

  • What should be the message logged by FunctionLogger? How configurable should it be?
  • What if some use-cases require applying same augmentation to both cost function and gradient? I think we should leave to the user's to ensure that such constraints are met. Another way would be to introduce additional common_augmentations which would contain all augmentations that would be applied to both cost function and gradient prior to applying specific augmentations.

@dexter2206 dexter2206 requested a review from a team September 1, 2021 13:40
@codecov
Copy link

codecov bot commented Sep 1, 2021

Codecov Report

Merging #417 (8edc45a) into dev (f0dd6e4) will increase coverage by 0.17%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev     #417      +/-   ##
==========================================
+ Coverage   90.16%   90.33%   +0.17%     
==========================================
  Files          59       60       +1     
  Lines        3354     3413      +59     
  Branches      553      556       +3     
==========================================
+ Hits         3024     3083      +59     
  Misses        222      222              
  Partials      108      108              
Impacted Files Coverage Δ
...thon/zquantum/core/cost_function_augmenntations.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f0dd6e4...8edc45a. Read the comment docs.


class _AttributePropagatingWrapper:
def __init__(self, function, additional_attribute_source, attribute_overrides):
object.__setattr__(self, "_function", function)
Copy link
Contributor

Choose a reason for hiding this comment

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

Its worth commenting (for all magic methods) in code why you need to modify them, so that future developers understand and don't break the functionality you are implementing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added some documentation in the docstrings and several comments. I allowed myself to skip explaining why init and call are needed since those are rather obvious (but feel free to disagree). Let me know if the explanations provided now are sufficient.


@abc.abstractmethod
def _act(self, result, params):
pass
Copy link
Contributor

@pcarinhas pcarinhas Sep 1, 2021

Choose a reason for hiding this comment

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

Shouldn't this raise a NotImplemtedError ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't have to, because you are not able to call this method unless you implement some concrete subclass of ConditionalSideEffect. However, after adding docstring the pass statement is no longer needed too, so I removed it.

@dexter2206 dexter2206 requested a review from pcarinhas September 2, 2021 11:09
@dexter2206 dexter2206 merged commit fa4427e into dev Sep 2, 2021
@dexter2206 dexter2206 deleted the ZQS-721-cost-function-logger-poc branch September 2, 2021 15:06
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants