Issue860

Title Eager search: move fetch_next_node() into step(), reuse evaluation context
Priority wish Status resolved
Superseder Nosy List cedric, florian, jendrik, malte, silvan
Assigned To silvan Keywords
Optional summary

Created on 2018-10-29.11:25:00 by silvan, last changed by silvan.

Messages
msg8766 (view) Author: silvan Date: 2019-04-17.12:24:38
Done.
msg8765 (view) Author: malte Date: 2019-04-16.23:19:58
Looks good to me. I only re-checked very superficially, but we checked the
search code previously with experiments, and if there is a problem with any of
the other changes, the buildbot will complain loudly. So I think this is ready
to be merged.
msg8764 (view) Author: silvan Date: 2019-04-16.17:09:11
That's what I meant, yes. Reverted the change and did the other changes.
msg8763 (view) Author: malte Date: 2019-04-15.21:56:04
I think it is header-only (at least according to
https://stackoverflow.com/questions/13604090/which-boost-libraries-are-header-only),
but perhaps you meant that it isn't single-header?

Looking at the diff it has lots of other boost dependencies, so we would have to
add dozens of files. There are 15 boost headers that are directly included, and
these might have further dependencies themselves. Yes, this is probably why we
have our own version, and in this case I wouldn't move it to ext but revert to
what we had before for "any". (Sorry!) If anyone else would rather open all
necessary boost files, I'm not dead against it; we could discuss it. What I'd
rather not add is an external dependency on boost, though.

To avoid falling into this trap again, perhaps we should add a comment near the
top of our version of "any" explaining *why* we don't use boost::any (because
that has so many dependencies that it would require adding lots of files).
msg8762 (view) Author: silvan Date: 2019-04-15.10:50:03
This is the new pull-request:
https://bitbucket.org/SilvanS/fd-dev/pull-requests/48/issue860/diff

I just realized that boost::any is *not* header-only (it compiled on my system
because I have a boost installation around), which is probably the reason why we
originally came up with our own copy of it. Do we still want to switch to that
version of any?
msg8759 (view) Author: malte Date: 2019-04-13.18:53:44
Yes. It looks like the pull request doesn't receive new commits because it has
been merged, which is something I didn't notice until I looked at
https://bitbucket.org/SilvanS/fd-dev/pull-requests/.

I left some further comments directly with the relevant commits, as I cannot
comment on them as part of the pull request. I think only you see comments
posted on these commits, so if you reply, I don't think anyone will get notified.
msg8758 (view) Author: silvan Date: 2019-04-13.17:53:09
That's strange. Does this direct link work?
https://bitbucket.org/SilvanS/fd-dev/commits/7ddde0f0fa3a965cc1c3925a297963078e168a3a
msg8757 (view) Author: malte Date: 2019-04-13.13:03:33
I don't see new commits in the pull request since March 20.
msg8756 (view) Author: silvan Date: 2019-04-12.13:28:46
Ok, I replaced any.h by boost's any.hpp. Anyone who wants to have another look?
msg8755 (view) Author: malte Date: 2019-04-09.17:48:48
I think simple clean-up that doesn't make the reviewing more complicated can be
done at the same time, but I don't care much either way. But I think we should
do it.
msg8754 (view) Author: silvan Date: 2019-04-09.15:34:09
Changed the include form. I think removing any.h and using boost's any.hpp
should happend in a different issue, or shouldn't it?
msg8751 (view) Author: malte Date: 2019-04-04.14:39:53
If we decide to keep "ext" around, I recommend we also move "any.h" to ext and
replace our version with the original version. I don't think there's a good
reason to treat "any" and "optional" differently.
msg8750 (view) Author: jendrik Date: 2019-04-04.14:38:19
We discussed this today and decided to leave the file in the "ext" directory.
The only TODO left for this issue is to use #include <...> for all files in "ext".
msg8743 (view) Author: silvan Date: 2019-03-22.15:48:21
Done. So all that remains is to discuss how to integrate std::optional.
msg8742 (view) Author: malte Date: 2019-03-22.15:20:50
Agreed. (But before merging, please fix the planner configurations in the
experiments that will break when we fix the errors in the option parser:
"astar(lmcut)" and "astar(blind)".)
msg8741 (view) Author: jendrik Date: 2019-03-22.09:21:04
I agree.
msg8740 (view) Author: silvan Date: 2019-03-22.08:41:46
Everything looks correct:
https://ai.dmi.unibas.ch/_tmp_files/sieverss/issue860-v2-issue860-base-issue860-v2-compare.html
msg8739 (view) Author: silvan Date: 2019-03-21.17:42:18
Ok. I actually wanted to go with lmcount but thought it'd need an LP solver for
admissible=true, but that is only necessary for optimal=true.
msg8738 (view) Author: malte Date: 2019-03-21.17:35:40
The first one is good, except that it's a parser bug that we accept this. It
should be "lmcut()", not "lmcut".

The second one isn't so good, as LM-Cut will never change between evaluations.
You can use the seq-opt-bjolp configuration. (If you don't want the hassle of
passing in driver options, just copy the configuration from driver/aliases.py.)
msg8737 (view) Author: silvan Date: 2019-03-21.17:32:22
Would
"astar-lmcut", ["--search", "astar(lmcut)"]), # inconsistent heuristic to test
re-opening
"astar-blind-lazy-lmcut", ["--search", "astar(blind, lazy_evaluator=lmcut)"]), #
test lazy evaluator
provide the information you want?
msg8711 (view) Author: jendrik Date: 2019-03-20.13:42:02
I think it would be good to run a small experiment testing the things you mention.
msg8710 (view) Author: malte Date: 2019-03-20.12:30:54
Sounds good. Are we confident about the correctness of the change? The
experiment was about speed, not correctness; it didn't exercise the bulk of the
code in the diff (lazy evaluators, reopening due to inconsistent heuristics).

If you (plural) have no concerns there, I think we can merge this once we've
decided what to do with "optional".
msg8709 (view) Author: silvan Date: 2019-03-20.09:43:38
Addressed them. Marking this as waiting for the outcome of the discussion.
msg8708 (view) Author: jendrik Date: 2019-03-20.00:21:29
I had a look and left a few comments. I think the change makes the code cleaner
and simplifies further refactorings.

I added discussing "optional" to the Fast Downward meeting agenda.
msg8706 (view) Author: malte Date: 2019-03-19.18:51:35
I am somewhat in favour of the idea in general, but would like to discuss
whether or not we want to include "optional" in our codebase in this fashion
among our wider group of developers, not just in the context of this issue.

There is also the more technical question whether we want to add it to the "ext"
directory (like in your pull request) or make it a "regular" part of the code,
like we did for our version of "any".

Independently of these more general questions, can someone review Silvan's pull
request? I'm mostly interested in whether this makes the code cleaner, or
facilitates making it cleaner in the future.
msg8705 (view) Author: silvan Date: 2019-03-19.16:57:16
This works indeed. I implemented and ran an experiment:
https://ai.dmi.unibas.ch/_tmp_files/sieverss/issue860-v2-issue860-base-issue860-v2-compare.html

No changes, also no more small increase in runtime as when using unique_ptr for
search nodes.

Should we hence include this header-only file that provides C++11-support for
std::optional?
msg8704 (view) Author: malte Date: 2019-03-19.15:06:22
We could consider adding assignment to SearchNode. However, it's possible to use
std::optional with types without copy assignment by using emplace instead of
operator=. The following works for me:

g++-6 -std=c++1z optional_test.cc  -o optional_test && ./optional_test

where optional_test.cc is:

====================================================================================

#include <experimental/optional>

class X {
    int a;
    int b;
public:
    X(int a, int b) :
        a(a), b(b) {
    }
    X &operator=(const X& other) = delete;
};

int main(int, char **) {
    std::experimental::optional<X> optional_x;
    X x(1, 2);
    // This does not work:
    // optional_x = x;
    // This does work:
    optional_x.emplace(x);
    return 0;
}
msg8703 (view) Author: silvan Date: 2019-03-19.12:27:21
>It's under the most liberal possible licence. I haven't looked into it much more
>deeply, let alone tested it.
It compiles with our setting, so we could include it also for other use cases.

>I'm not even sure it would address our problem here, i.e., if search nodes
>support the necessary operations to use it here. But conceptually it's what I
>always wanted when trying to get rid of this particular source of ugliness in
>the search algorithms.
It doesn't help us with our problem because we would still need to be able to
assign SearchNode objects, which we can't.

How should we proceed here?
msg8630 (view) Author: malte Date: 2019-03-07.18:36:09
Following up on today's live discussion: I googled for "standalone std::optional
implementation for c++11" (not in quotes) and found this, which claims to be a
single-header implementation that supports all our supported compilers:

https://github.com/TartanLlama/optional

It's under the most liberal possible licence. I haven't looked into it much more
deeply, let alone tested it.
msg8627 (view) Author: silvan Date: 2019-03-07.11:36:10
std::experimental::optional is not available in what we support, and neither is
the "compliant and widely-used C++11-based implementation by Andrei Krzemienski"
because it also uses std::optional (I don't know what stackoverflow claims that
this supports C++11, because the github page only promises partial C++11
support). So to further pursue that idea, we would need to dig deeper to get an
implementation of std::optional.

In lazy search, there is no need to fetch a next node and potentially re-assign
it. It also has a member EvaluationContext current_evaluation_context, which is
being re-used across method (I think). So no need to take any action here.
msg8618 (view) Author: malte Date: 2019-03-05.23:18:00
Besides possible performance gains, I'd like std::optional (or
std::experimental::optional) because it captures the intent directly (we could
get rid of the comment explaining why we use a unique_ptr here), and I think it
could be useful in other parts of the code, too.

I'm not even sure it would address our problem here, i.e., if search nodes
support the necessary operations to use it here. But conceptually it's what I
always wanted when trying to get rid of this particular source of ugliness in
the search algorithms.

If std::experimental::optional is available in the C++ versions we want to
support (I'm not sure we can use all C++14 features yet), I'd like to try it
out. Otherwise, I'm fine either way.

Is there a similar hack in lazy search, too?

Regarding the runtime changes, they are a bit of a pity, but in my opinion not a
show-stopper. The overhead will be less pronounced in anything other than blind
search.
msg8610 (view) Author: silvan Date: 2019-03-05.14:53:05
Here are the results with blind search:
https://ai.dmi.unibas.ch/_tmp_files/sieverss/issue860-v1-issue860-base-issue860-v1-compare.html
The search becomes slightly slower, but not very badly, I think.

Should we still go with the std::optional suggestion? According to
https://codereview.stackexchange.com/questions/175882/optionalt-implementation,
in C++14, we could directly use std::experimental::optional. (If we didn't want
to, we could use the implementation from here: https://github.com/akrzemi1/Optional)
msg8605 (view) Author: malte Date: 2019-03-05.10:31:38
Dynamically allocating memory for every search node that is not conceptually
necessary isn't great, but if it helps simplify the code for now, we can give it
a shot. It would be nice to check the performance impact of this change in
isolation, though. The impact is probably minimal, but it's better to be sure.
Testing with A* + blind is enough.

A better solution would be to use std::optional, but we haven't arrived at C++17
yet, I think. An option would be to include an external implementation of
std::optional as a stopgap measure, like we do with our version of "any" (that
substitutes for std::any in newer standards) and our version of
"make_unique_ptr" (that substituted for std::make_unique in newer standards).
msg8604 (view) Author: silvan Date: 2019-03-05.10:06:02
I found a way to circumvent the problem using unique_ptr for SearchNodes. That
means that we no longer need the fetch_next_node method and that we can re-use
the EvaluationContext for lazy evaluators when reporting f-value statistics.
msg8556 (view) Author: jendrik Date: 2019-02-27.14:57:44
Maybe you can find a hacked first version that we can later improve upon?
msg8553 (view) Author: silvan Date: 2019-02-27.14:50:01
I don't remember if we came to a conclusion during the retreat regarding of how
to continue here. I think that we more or less agreed on the long-term plan
regarding when and how to pack/unpack states, but I still don't see an easy way
to address this first, small issue here.
msg8466 (view) Author: silvan Date: 2019-01-16.12:30:21
I started working on this but realized that since SearchNode and
EvaluationContext can't be default-constructed or assigned, this cannot be done
as easily as we anticipated.

https://bitbucket.org/SilvanS/fd-dev/pull-requests/43/issue860/diff
msg8028 (view) Author: silvan Date: 2018-10-29.11:25:00
In the last Fast Downward meeting, we discussed where and how to unpack states
(see meta issue401). A first step to simplify existing code will be to merge the
functionality of fetch_next_node() of eager_search into step(), allowing to
reuse an existing evaluation context.
History
Date User Action Args
2019-04-17 12:24:38silvansetstatus: testing -> resolved
messages: + msg8766
2019-04-16 23:19:58maltesetmessages: + msg8765
2019-04-16 17:09:11silvansetmessages: + msg8764
2019-04-15 21:56:04maltesetmessages: + msg8763
2019-04-15 10:50:03silvansetmessages: + msg8762
2019-04-13 18:53:44maltesetmessages: + msg8759
2019-04-13 17:53:09silvansetmessages: + msg8758
2019-04-13 13:03:33maltesetmessages: + msg8757
2019-04-12 13:28:46silvansetmessages: + msg8756
2019-04-09 17:48:48maltesetmessages: + msg8755
2019-04-09 15:34:09silvansetmessages: + msg8754
2019-04-04 14:39:53maltesetmessages: + msg8751
2019-04-04 14:38:19jendriksetmessages: + msg8750
summary: Waiting for the outcome of the discussion of if and how to integrate std::optional. ->
2019-03-22 15:48:21silvansetmessages: + msg8743
2019-03-22 15:20:50maltesetmessages: + msg8742
2019-03-22 09:21:04jendriksetmessages: + msg8741
2019-03-22 08:41:46silvansetmessages: + msg8740
2019-03-21 17:42:18silvansetmessages: + msg8739
2019-03-21 17:35:40maltesetmessages: + msg8738
2019-03-21 17:32:22silvansetstatus: reviewing -> testing
messages: + msg8737
2019-03-20 13:42:02jendriksetmessages: + msg8711
2019-03-20 12:30:54maltesetmessages: + msg8710
2019-03-20 09:43:38silvansetmessages: + msg8709
summary: Waiting for the outcome of the discussion of if and how to integrate std::optional.
2019-03-20 00:21:29jendriksetmessages: + msg8708
2019-03-19 18:51:35maltesetmessages: + msg8706
2019-03-19 16:57:16silvansetmessages: + msg8705
2019-03-19 15:06:22maltesetmessages: + msg8704
2019-03-19 12:27:21silvansetmessages: + msg8703
2019-03-07 18:36:09maltesetmessages: + msg8630
2019-03-07 11:36:10silvansetmessages: + msg8627
2019-03-05 23:18:00maltesetmessages: + msg8618
2019-03-05 14:53:05silvansetstatus: in-progress -> reviewing
messages: + msg8610
2019-03-05 10:31:38maltesetmessages: + msg8605
2019-03-05 10:06:02silvansetmessages: + msg8604
2019-02-27 14:57:44jendriksetmessages: + msg8556
2019-02-27 14:50:01silvansetmessages: + msg8553
2019-01-16 12:30:21silvansetmessages: + msg8466
2018-10-29 11:33:12cedricsetnosy: + cedric
2018-10-29 11:25:00silvancreate