Improved readability of ApproximateBestSubset #7183

pull murchandamus wants to merge 1 commits into bitcoin:master from murchandamus:Fix-#7182 changing 1 files +2 −1
  1. murchandamus commented at 5:36 PM on December 7, 2015: contributor

    vValue is sorted into ascending order before ApproximateBestSubset(...) is called.

    Currently, after a new best set is found, the final element that was added gets removed from the set, and the inner loop continues to search through the remainder of vValue for a better set. It is however impossible for a better set to be achieved with a later element in vValue: As vValue is sorted in ascending order, any set formed with a later element will be of same size or bigger.

    Therefore, the lines 1628 & 1629 are obsolete, and the inner loop should also stop on fReachedTarget.

  2. laanwj added the label Wallet on Dec 8, 2015
  3. laanwj renamed this:
    Removed obsolete lines of code, broke continuation of loop.
    ApproximateBestSubset: Removed obsolete lines of code, broke continuation of loop
    on Dec 8, 2015
  4. maflcko commented at 5:19 PM on December 9, 2015: member

    vValue is not sorted in ascending order, the whole algorithm wouldn't make sense if it was...

  5. murchandamus commented at 9:31 PM on December 9, 2015: contributor

    @MarcoFalke: Sorry, apparently the links always refer to the current version and shift around because of that, however in CWallet::SelectCoinsMinConf(…) there are the following lines:

    // Solve subset sum by stochastic approximation
    sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
    vector<char> vfBest;
    CAmount nBest;
    
    ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest);
    

    As you can see vValue appears to get sorted into ascending order right before ApproximateBestSubset(…) gets called. I do think that it used to be different when I first started my other PR (September last year) though, because right now it does increase the probability of small inputs to get selected.

  6. laanwj commented at 11:17 AM on December 10, 2015: member

    vValue is not sorted in ascending order, the whole algorithm wouldn't make sense if it was...

    It actually is. (or is CompareValueOnly doing something else than I assumed it does? that'd be confusing...) Nope:

    struct CompareValueOnly
    {
        bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1,
                        const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const
        {
            return t1.first < t2.first;
        }
    };
    

    If you say this sorts it in descending order, I don't see where that happens.

  7. maflcko commented at 12:23 PM on December 10, 2015: member

    If you say this sorts it in descending order, I don't see where that happens.

    Right in the line where std::sort() is called: https://github.com/bitcoin/bitcoin/blob/5dc63ed1ca8aca62f28881ba9ef996d4036a23ea/src/wallet/wallet.cpp#L1719

    r means reverse and the reverse of ascending is descending?

  8. maflcko commented at 12:24 PM on December 10, 2015: member

    links always refer to the current version and shift around because of that @Xekyo If you want to link on GitHub, don't forget to press the y-Key before copy pasting the link

  9. morcos commented at 3:49 PM on December 10, 2015: member

    Yikes, that's easy to overlook, perhaps a comment.

  10. maflcko commented at 3:57 PM on December 10, 2015: member

    And a unit test because this PR should not pass travis in the first place.

  11. maflcko commented at 1:20 PM on December 12, 2015: member

    @Xekyo Can you take a look at this and add a comment above the "sort()-line"?

  12. laanwj commented at 1:24 PM on December 14, 2015: member

    Yikes, that's easy to overlook, perhaps a comment.

    Absolutely. I also had no idea that you could pass reverse iterators to std::sort and it would just work.

  13. murchandamus commented at 1:32 PM on January 3, 2016: contributor

    @MarcoFalke: TIL. I was unaware of that behaviour of sort(…) with reverse iterators. From what I’m reading using reverse iterators isn’t very efficient, though.

    Instead of using reverse iterators, one could replace the line

     sort(vValue.rbegin(), vValue.rend(), CompareValueOnly());
    

    with these two

    sort(vValue.begin(), vValue.end(), CompareValueOnly());
    reverse(vValue.begin(), vValue.end());
    

    It would become much more readable, wouldn’t need a comment to clarify, and perhaps perform even faster.

  14. maflcko commented at 1:38 PM on January 3, 2016: member

    Sounds ok to me. Are you planning to write the unit test as well?

  15. murchandamus commented at 1:45 PM on January 3, 2016: contributor

    @MarcoFalke: I could do that, yet I’m unsure what one would want to test. Since the sorting operation is in the middle of CWallet::SelectCoinsMinConf(…), it’s would require quite a bit of refactoring to isolate as vValue is only a transient variable in that function.

  16. murchandamus force-pushed on Jan 3, 2016
  17. maflcko commented at 2:31 PM on January 3, 2016: member

    @Xekyo I mean a "high level" test like #7193, such that your initial commit will fail travis. (Would you mind to post the inital diff or commit hash for reference and testing, I forgot to save it.)

  18. murchandamus commented at 7:57 PM on January 3, 2016: contributor

    @MarcoFalke: Unfortunately, I also overwrote my commit when I rebased my branch (perhaps prematurely) and pushed it to my fork. Would it make sense to redo them and push them onto another branch?

    I’ve added a test.

  19. maflcko commented at 10:38 PM on January 3, 2016: member

    Provided by @Xekyo on IRC: $ git reflog show Fix-#7182@{one.day.ago}

    b9ecfc7

    diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
    index d23d54e..3d1f58c 100644
    --- a/src/wallet/wallet.cpp
    +++ b/src/wallet/wallet.cpp
    @@ -1605,7 +1605,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
             bool fReachedTarget = false;
             for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
             {
    -            for (unsigned int i = 0; i < vValue.size(); i++)
    +            for (unsigned int i = 0; i < vValue.size() && !fReachedTarget; i++)
                 {
                     //The solver here uses a randomized algorithm,
                     //the randomness serves no real security purpose but is just
    @@ -1625,8 +1625,6 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
                                 nBest = nTotal;
                                 vfBest = vfIncluded;
                             }
    -                        nTotal -= vValue[i].first;
    -                        vfIncluded[i] = false;
                         }
                     }
                 }
    
  20. murchandamus renamed this:
    ApproximateBestSubset: Removed obsolete lines of code, broke continuation of loop
    Improved readability of ApproximateBestSubset.
    on Jan 3, 2016
  21. murchandamus renamed this:
    Improved readability of ApproximateBestSubset.
    Improved readability of ApproximateBestSubset, added test to check for suboptimal result of selection.
    on Jan 3, 2016
  22. in src/wallet/test/wallet_tests.cpp:None in c2e38d6895 outdated
      76 | +    for (int i = 0; i < 1000; i++)
      77 | +        add_coin(3 * CENT);
      78 | +    for (int i = 0; i < 1000; i++)
      79 | +        add_coin(1000 * CENT);
      80 | +
      81 | +    BOOST_CHECK(wallet.SelectCoinsMinConf(1000001 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
    


    maflcko commented at 11:54 PM on January 4, 2016:

    This will select quite a bunch of the 3ct coins, I don't think you want this. Just reduce the number to 1 like #7293


    maflcko commented at 11:55 PM on January 4, 2016:

    @Xekyo You can either get the test case from #7293 and include it here or remove the test case in this pull.


    murchandamus commented at 3:29 PM on January 5, 2016:

    I’ve ACKed #7293 and will remove the test case here.

  23. murchandamus renamed this:
    Improved readability of ApproximateBestSubset, added test to check for suboptimal result of selection.
    Improved readability of ApproximateBestSubset
    on Jan 5, 2016
  24. murchandamus force-pushed on Jan 5, 2016
  25. maflcko commented at 4:45 PM on January 5, 2016: member

    utACK 047cf77e324817594ce58e0ff53e5d817d1a9bc1.

    Nit: you could use std::sort and std:reverse to prevent follow up commits.

  26. Improved readability of sorting for coin selection.
    Future proofing added lines
    96efcadfc0
  27. murchandamus force-pushed on Jan 5, 2016
  28. murchandamus commented at 9:05 PM on January 5, 2016: contributor

    Edited to include the nit. :)

  29. maflcko commented at 9:32 PM on January 5, 2016: member

    trivial re-ACK 96efcad

  30. jonasschnelli commented at 1:17 PM on January 20, 2016: contributor

    utACK 96efcadfc0d8a84066982533c676072d3b5d8314

  31. laanwj merged this on Jan 20, 2016
  32. laanwj closed this on Jan 20, 2016

  33. laanwj referenced this in commit b92ea98503 on Jan 20, 2016
  34. laanwj commented at 2:55 PM on January 20, 2016: member

    utACK 96efcad

  35. luke-jr commented at 2:59 AM on February 12, 2016: member

    Is there some reason not to just invert the CompareValueOnly function?

  36. laanwj commented at 1:09 PM on February 12, 2016: member

    And call it ReverseCompareValueOnly, yes that would have been the other option. But let's leave it as it is now, there's no need to shedpaint this.

  37. codablock referenced this in commit b3b432330c on Sep 16, 2017
  38. codablock referenced this in commit 068c4ef6e1 on Sep 19, 2017
  39. codablock referenced this in commit 4e2f0c2596 on Dec 9, 2017
  40. codablock referenced this in commit 59db2fda16 on Dec 9, 2017
  41. bitcoin locked this on Sep 8, 2021
  42. murchandamus deleted the branch on Oct 6, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-17 06:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me