Skip to content

VSD - Cross-representation expression evaluation #5880

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

Merged
merged 22 commits into from
Mar 6, 2021

Conversation

jezhiggins
Copy link
Contributor

@jezhiggins jezhiggins commented Mar 2, 2021

Enable the variable-sensitivity domain to evaluate expressions involving different value representations.

For example, this enables evaluation of the expression
a + b
where
a is a constant 3
b is a value-set { 2, 4, 6 }
returning a new value-set of { 5, 7, 9 }

  • any are value sets, iterate over all of the combinations and dispatch for each of these (producing a value set to contain all of the results)
  • mixed constant and interval, convert all constants to intervals and handle as all intervals.
  • all interval ao, have to do interval arithmetic
  • all constant ao, can simply substitute (if not top) and simplify to get the constant.

All existing behaviour is retained - this is new additional behaviour.


Rather than each representation having its own expression_transform everything is now routed through abstract_value_objectt::expression_transform, which then dispatches according to the operand representations. For all constants, and all interval expressions, the implementation is essentially identical constant_abstract_valuet::expression_transform and interval_abstract_valuet::expression_transform . The value_set evaluation is broadly similar to what we had before, building each combination of operands. Each representation now has a value_range, and the value_set evaluation uses this to build the combinations in a representation agnostic way.

The focus of this PR has been on the interaction of value-sets and constants. There will be follow-up PR focussing on intervals - this may only be additional test-cases, but in any case will be rather less substantial.

The commit where the action happens is 8329afd Everything before that is essentially preparatory, everything after is refactoring enabled by this change.

merging value_sets with value_sets
The index_ranget has, by C++ standards, an unusual interface more akin
to something you'd get on a C# enumerator. This is the first step to
making it more container-like, with begin()/end() member functions
returning iterators.

With this commit, the iterators are input-iterator like, in that they
can only be traversed once.
index_ranget is now only returns its begin and end
iterators. It's now returned as a value, rather than through a
shared_ptr, as its lifetime will naturally be scope limited and,
as described below, polymorphic behaviour is hidden inside. This
makes it more natural to use too, as we can just write

   for (const auto &index : range)

rather than having to dereference it.

It can now be repeatedly iterated, rather than the one
and done it was in the previous commit.

Behind it, the classes that do the actual work of enumerating the
the different representations have been split out from input_ranget.
There is no longer any need to share these objects, so they are
instantiated using unique_ptr rather than shared_ptr.
Iterates over the values represented by the abstract object. For
constants and intervals, this will be the object itself. For value sets,
it will be the values in the set.

Rework value_set expression evaluation in terms of value_ranget. This
enables evaluation with mixed value_sets and constants.

Made value_set_abstract_object implementation functions static.

There's a bodge in value_set_abstract_objectt::unwrap_operands to
workaround what would otherwise be an invariant violation. As we
implement cross-representation evaluation, we'll hit these exceptions
but once the work is complete they should all be eliminated.
Simple tests where all operands are constant_abstract_valuets, capturing
and confirming existing behaviour.
Initial unit tests - currently fails
Implement abstract_value_objectt::expression_transform, and prevent
further overriding. Within that, dispatch according to the types of the
operands -

* any are value sets, iterate over all of the combinations and
  dispatch for each of these, producing a value set to contain
  all of the results
* mixed constant and interval, convert all constants to intervals
  and handle as all intervals
* all interval, do interval arithmetic
* all constant, substitute and simplify
The constants_evaluator class wraps up what was previous contained
in constant_abstract_valuet::expression_transform. While it could have
been implemented with free functions, using a class allows us to
restrict scope, refactor to clearer code by reducing the number of
parameters flying around.

The process of building the class signposted a number of additional
small clean ups that I might have otherwise overlooked.
Wrap up interval evaluation in a wrapper class.

Most significant change is simplifying the process of
coercing constants to intervals. Rather than trying to bail out early if
we hit a top value or something which can't be converted, go over the
whole list of operands, skipping any we can't convert. Check afterwards
if we're missing some and then decide what to do.
for_each_comb doesn't need to be a template - it's only used once, so we
know the type of the collection and we know the operation to be
performed.
When we create values through the factory, the representation used is
determined by the factory configuration. Up until now, that
configuration has always lined up with the representation - eg if we were
evaluating using intervals, then the factory is creating intervals.

This is no longer the case. As we move forward with cross-representation
evaluation, it's entirely possible that the factory configuration does
_not_ match the representation we have in hand during an evaluation.
Consequently, if we need a new constant value we should directly create
it.

As we leave the expression_transform, we use the factory to wrap any
required context around the returned object.
Prevent repeated calls to obj->to_interval() by returning a list of
expressions in the first place. Removes a level of indirection in the
subsequent code.
@jezhiggins jezhiggins force-pushed the vsd-value-sets-and-constants branch from 79736ef to 2fa8d96 Compare March 2, 2021 11:21
@codecov
Copy link

codecov bot commented Mar 2, 2021

Codecov Report

Merging #5880 (2fa8d96) into develop (42896e7) will increase coverage by 0.07%.
The diff coverage is 95.95%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #5880      +/-   ##
===========================================
+ Coverage    72.90%   72.98%   +0.07%     
===========================================
  Files         1423     1429       +6     
  Lines       154159   154687     +528     
===========================================
+ Hits        112397   112899     +502     
- Misses       41762    41788      +26     
Impacted Files Coverage Δ
...yses/variable-sensitivity/abstract_environment.cpp 87.42% <ø> (ø)
...ses/variable-sensitivity/constant_abstract_value.h 100.00% <ø> (ø)
...ble-sensitivity/constant_pointer_abstract_object.h 100.00% <ø> (ø)
...e-sensitivity/variable_sensitivity_configuration.h 100.00% <ø> (ø)
...riable-sensitivity/variable_sensitivity_domain.cpp 87.11% <ø> (ø)
...-sensitivity/variable_sensitivity_object_factory.h 100.00% <ø> (ø)
unit/analyses/variable-sensitivity/eval.cpp 100.00% <ø> (ø)
...e-sensitivity/constant_pointer_abstract_object.cpp 86.51% <66.66%> (ø)
...s/variable-sensitivity/abstract_pointer_object.cpp 76.66% <70.00%> (ø)
...-sensitivity/value_set_pointer_abstract_object.cpp 78.82% <80.72%> (+18.82%) ⬆️
... and 39 more

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 ced2d39...2fa8d96. Read the comment docs.

Copy link
Collaborator

@martin-cs martin-cs left a comment

Choose a reason for hiding this comment

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

First off, thank you for this large and impressive refactoring. I've been through each of the commits and they all seem to be doing the right kind of thing. Given the issues with the existing code and the scale of the restructuring I favour merging this and then I will do a review over all of VSD and pick up any issues that remain. I think that is the most efficient way forward.

@martin-cs martin-cs merged commit fa12ca7 into diffblue:develop Mar 6, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants