int SignatureLeptonTagger::Train(Event const& event, boca::PreCuts const&, Tag tag)
{
    INFO0;
   std::vector<Lepton> leptons = event.Leptons().leptons();
    if (leptons.size() < 2) return 0;
   std::vector<Particle> particles = event.Partons().GenParticles();
   std::vector<Particle> lepton_particle = CopyIfParticles(particles, {Id::electron, Id::muon});
//     ERROR(lepton_particle);
    lepton_particle = CopyIfGrandMother(lepton_particle, Id::top);
//     ERROR(lepton_particle);
    std::vector<Lepton> final_leptons = CopyIfClose(leptons, lepton_particle);
//     ERROR(final_leptons);
    std::vector<Doublet> doublets = higgs_reader_.Multiplets(event);
    std::vector<Particle> higgses = CopyIfParticles(particles, {Id::higgs, Id::CP_violating_higgs});
    std::vector<Doublet> final_doublets = BestMatches(doublets, higgses, tag);

    std::vector<MultipletSignature<Quartet211>> quartets = Triples(final_leptons, final_doublets, [&](Singlet const& singlet_1, Singlet const& singlet_2, Doublet const& doublet) {
        MultipletSignature<Quartet211> quartet = Signature(doublet, singlet_1, singlet_2);
        quartet.SetTag(tag);
        return quartet;
    });
    DEBUG(quartets.size());
    if (tag == Tag::signal) quartets = ReduceResult(quartets, 1);
    DEBUG(quartets.size());
    return  SaveEntries(quartets);
}
int TopLeptonicPair::Train(boca::Event const& event, boca::PreCuts const&, Tag tag)
{
    INFO0;
    auto triplets = top_leptonic_reader_.Multiplets(event);
    DEBUG(triplets.size());
    auto particles = event.GenParticles();
    auto top_particles = CopyIfParticle(particles, Id::top);
    CHECK(top_particles.size() == 2, top_particles.size());
//    std::vector<Jet>neutrinos = CopyIfNeutrino(particles);
    if (top_particles.size() != 2 && tag == Tag::signal) DEBUG(particles.size());
    auto final_triplets = BestMatches(triplets, top_particles, tag);
//     CHECK(final_triplets.size()==2, final_triplets.size());
    auto sextets = UnorderedPairs(final_triplets, [](Triplet const & triplet_1, Triplet const & triplet_2) {
        Quartet22 quartet(Doublet(triplet_1.Singlet(), triplet_1.Doublet().Jet()), Doublet(triplet_2.Singlet(), triplet_2.Doublet().Jet()));
        if (quartet.Overlap()) throw Overlap();
        quartet.Doublet1().SetBdt(triplet_1.Bdt());
        quartet.Doublet2().SetBdt(triplet_2.Bdt());
        WimpMass wimp_mass;
        //             Insert(sextets, wimp_mass.Sextet(quartet, event.MissingEt(), neutrinos, tag));
        return wimp_mass.Fake(quartet);
    });

    if (tag == Tag::signal && sextets.size() > 1) {
        DEBUG(sextets.size());
        sextets = BestRapidity(sextets);
    }
    return SaveEntries(sextets);
}
int SignatureNeutral::Train(boca::Event const& event, PreCuts const&, Tag tag)
{
    INFO0;
    auto higgs = heavy_higgs_semi_reader_.Tagger().HiggsParticle(event, tag);
    auto sextets = heavy_higgs_semi_reader_.Multiplets(event);
    sextets = BestMatches(sextets, higgs, tag);

    auto doublets = jet_pair_reader_.Multiplets(event);
    auto bottoms = SortedByPt(jet_pair_reader_.Tagger().PairBottomQuarks(event, tag));

    auto particles = event.GenParticles();
    auto tops = CopyIfParticle(particles, Id::top);
    auto tops_even = CopyIfMother(tops, Id::heavy_higgs);
    auto tops_odd = CopyIfMother(tops, Id::CP_odd_higgs);
    auto top_higgs = Combine(tops_even, tops_odd);
    auto one_close_to_top = 0, two_close_to_top = 0;

    if (top_higgs.size() == 2) {

        for (auto const & doublet : doublets) {
            if ((Close<boca::Jet>(top_higgs.at(0))(doublet.Singlet1()) && Close<boca::Jet>(top_higgs.at(1))(doublet.Singlet2())) || (Close<boca::Jet>(top_higgs.at(1))(doublet.Singlet1()) && Close<boca::Jet>(top_higgs.at(0))(doublet.Singlet2()))) two_close_to_top++;
            if ((Close<boca::Jet>(top_higgs.at(0))(doublet.Singlet1()) || Close<boca::Jet>(top_higgs.at(1))(doublet.Singlet2())) || (Close<boca::Jet>(top_higgs.at(1))(doublet.Singlet1()) || Close<boca::Jet>(top_higgs.at(0))(doublet.Singlet2()))) one_close_to_top++;
        }
    }

//     ERROR(one_close_to_top, two_close_to_top);
    static auto close_to_top_ = 0;
    if (one_close_to_top == 6) {
        ++close_to_top_;
    }

    std::vector<Doublet> final_doublets;
    switch (tag) {
    case Tag::signal :
        if (bottoms.size() == 2) {

            for (auto const & doublet : doublets) {
                if ((Close<boca::Jet>(bottoms.at(0))(doublet.Singlet1()) && Close<boca::Jet>(bottoms.at(1))(doublet.Singlet2())) || (Close<boca::Jet>(bottoms.at(1))(doublet.Singlet1()) && Close<boca::Jet>(bottoms.at(0))(doublet.Singlet2()))) final_doublets.emplace_back(doublet);

            }
        } else ERROR(bottoms.size());
        break;
    case Tag::background :
        final_doublets = doublets;
        break;
    }

    static auto zero_doublets = 0;
    if (one_close_to_top < 6 && final_doublets.empty()) {
        ++zero_doublets;
    }

    std::vector<Octet62> octets;
    for (auto const & doublet : final_doublets) {
        for (auto const & sextet : sextets) {
            Octet62 octet(sextet, doublet);
            if (octet.Overlap()) continue;
            octet.SetTag(tag);
            octets.emplace_back(octet);
        }
    }
    static auto zero_octets = 0;
    if (one_close_to_top < 6 && !final_doublets.empty() && octets.empty()) {
        ++zero_octets;
    }
//     ERROR(close_to_top_, zero_doublets, zero_octets);

    if (tag == Tag::signal && octets.size() > 1) {
        INFO(octets.size());
        std::sort(octets.begin(), octets.end());
        octets.erase(octets.begin() + 1, octets.end());
    }

    return SaveEntries(octets);
}