Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

https://github.com/TakehideSoh/SAF
18 January 2026, 11:53:51 UTC
  • Code
  • Branches (4)
  • Releases (0)
  • Visits
    • Branches
    • Releases
    • HEAD
    • refs/heads/dev
    • refs/heads/main
    • refs/tags/v1.0-cmsb2023
    • refs/tags/v1.1-CMSB2023
    No releases to show
  • 83aaea6
  • /
  • cadical
  • /
  • src
  • /
  • gates.cpp
Raw File Download Save again
Take a new snapshot of a software origin

If the archived software origin currently browsed is not synchronized with its upstream version (for instance when new commits have been issued), you can explicitly request Software Heritage to take a new snapshot of it.

Use the form below to proceed. Once a request has been submitted and accepted, it will be processed as soon as possible. You can then check its processing state by visiting this dedicated page.
swh spinner

Processing "take a new snapshot" request ...

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
  • revision
  • snapshot
origin badgecontent badge
swh:1:cnt:5b9e0551ee958376bcdd3468ca5748e1f554163b
origin badgedirectory badge
swh:1:dir:01d80ce94d8f49344a6b25660f682eedd134ff96
origin badgerevision badge
swh:1:rev:d26cc9f94a4f79c046ee0cdd3a127a44f7b443b6
origin badgesnapshot badge
swh:1:snp:d3fcf0e446f52630e867f11dee4c2c828bf46951

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
  • revision
  • snapshot
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Tip revision: d26cc9f94a4f79c046ee0cdd3a127a44f7b443b6 authored by TakehideSoh on 23 June 2023, 07:02:26 UTC
Merge pull request #2 from TakehideSoh/dev
Tip revision: d26cc9f
gates.cpp
#include "internal.hpp"

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// As in our original SATeLite published at SAT'05 we are trying to find
// gates in order to restrict the number of resolutions that need to be
// tried.  If there is such a gate, we only need to consider resolvents
// among gate and one non-gate clauses.  Resolvents between definitions will
// be tautological anyhow and resolvents among non-gates can actually be
// shown to be redundant too.

/*------------------------------------------------------------------------*/

// The next function returns a non-zero if the clause 'c', which is assumed
// to contain the literal 'first', after removing falsified literals is a
// binary clause.  Then the actual second literal is returned.

int
Internal::second_literal_in_binary_clause (Eliminator & eliminator,
                                           Clause * c, int first)
{
  assert (!c->garbage);
  int second = 0;
  for (const auto & lit : *c) {
    if (lit == first) continue;
    const signed char tmp = val (lit);
    if (tmp < 0) continue;
    if (tmp > 0) {
      mark_garbage (c);
      elim_update_removed_clause (eliminator, c);
      return 0;
    }
    if (second) { second = INT_MIN; break; }
    second = lit;
  }
  if (!second) return 0;
  if (second == INT_MIN) return 0;
  assert (active (second));
#ifdef LOGGING
  if (c->size == 2) LOG (c, "found binary");
  else LOG (c, "found actual binary %d %d", first, second);
#endif
  return second;
}

/*------------------------------------------------------------------------*/

// Mark all other literals in binary clauses with 'first'.  During this
// marking we might also detect hyper unary resolvents producing a unit.
// If such a unit is found we propagate it and return immediately.

void Internal::mark_binary_literals (Eliminator & eliminator, int first) {

  if (unsat) return;
  if (val (first)) return;
  if (!eliminator.gates.empty ()) return;

  assert (!marked (first));
  assert (eliminator.marked.empty ());

  const Occs & os = occs (first);
  for (const auto & c : os) {
    if (c->garbage) continue;
    const int second =
      second_literal_in_binary_clause (eliminator, c, first);
    if (!second) continue;
    const int tmp = marked (second);
    if (tmp < 0) {
      LOG ("found binary resolved unit %d", first);
      assign_unit (first);
      elim_propagate (eliminator, first);
      return;
    }
    if (tmp > 0) {
      LOG (c, "duplicated actual binary clause");
      elim_update_removed_clause (eliminator, c);
      mark_garbage (c);
      continue;
    }
    eliminator.marked.push_back (second);
    mark (second);
    LOG ("marked second literal %d in binary clause %d %d",
      second, first, second);
  }
}

// Unmark all literals saved on the 'marked' stack.

void Internal::unmark_binary_literals (Eliminator & eliminator) {
  LOG ("unmarking %zd literals", eliminator.marked.size ());
  for (const auto & lit : eliminator.marked)
    unmark (lit);
  eliminator.marked.clear ();
}

/*------------------------------------------------------------------------*/

// Find equivalence for 'pivot'.  Requires that all other literals in binary
// clauses with 'pivot' are marked (through 'mark_binary_literals');

void Internal::find_equivalence (Eliminator & eliminator, int pivot) {

  if (!opts.elimequivs) return;

  assert (opts.elimsubst);

  if (unsat) return;
  if (val (pivot)) return;
  if (!eliminator.gates.empty ()) return;

  mark_binary_literals (eliminator, pivot);
  if (unsat || val (pivot)) goto DONE;

  for (const auto & c : occs (-pivot)) {

    if (c->garbage) continue;

    const int second =
      second_literal_in_binary_clause (eliminator, c, -pivot);
    if (!second) continue;
    const int tmp = marked (second);
    if (tmp > 0) {
      LOG ("found binary resolved unit %d", second);
      assign_unit (second);
      elim_propagate (eliminator, second);
      if (val (pivot)) break;
      if (unsat) break;
    }
    if (tmp >= 0) continue;

    LOG ("found equivalence %d = %d", pivot, -second);
    stats.elimequivs++;
    stats.elimgates++;

    LOG (c, "first gate clause");
    assert (!c->gate);
    c->gate = true;
    eliminator.gates.push_back (c);

    Clause * d = 0;
    const Occs & ps = occs (pivot);
    for (const auto & e : ps) {
      if (e->garbage) continue;
      const int other =
        second_literal_in_binary_clause (eliminator, e, pivot);
      if (other == -second) { d = e; break; }
    }
    assert (d);

    LOG (d, "second gate clause");
    assert (!d->gate);
    d->gate = true;
    eliminator.gates.push_back (d);

    break;
  }

DONE:
  unmark_binary_literals (eliminator);
}

/*------------------------------------------------------------------------*/

// Find and gates for 'pivot' with a long clause, in which the pivot occurs
// positively.  Requires that all other literals in binary clauses with
// 'pivot' are marked (through 'mark_binary_literals');

void Internal::find_and_gate (Eliminator & eliminator, int pivot) {

  if (!opts.elimands) return;

  assert (opts.elimsubst);

  if (unsat) return;
  if (val (pivot)) return;
  if (!eliminator.gates.empty ()) return;

  mark_binary_literals (eliminator, pivot);
  if (unsat || val (pivot)) goto DONE;

  for (const auto & c : occs (-pivot)) {

    if (c->garbage) continue;
    if (c->size < 3) continue;

    bool all_literals_marked = true;
    unsigned arity = 0;
    int satisfied = 0;

    for (const auto & lit : *c) {
      if (lit == -pivot) continue;
      assert (lit != pivot);
      signed char tmp = val (lit);
      if (tmp < 0) continue;
      if (tmp > 0) { satisfied = lit; break; }
      tmp = marked (lit);
      if (tmp < 0) { arity++; continue; }
      all_literals_marked = false;
      break;
    }

    if (!all_literals_marked) continue;

    if (satisfied) {
      LOG (c, "satisfied by %d candidate base clause", satisfied);
      mark_garbage (c);
      continue;
    }

#ifdef LOGGING
    if (opts.log) {
      Logger::print_log_prefix (this);
      tout.magenta ();
      printf ("found arity %u AND gate %d = ", arity, -pivot);
      bool first = true;
      for (const auto & lit : *c) {
        if (lit == -pivot) continue;
        assert (lit != pivot);
        if (!first) fputs (" & ", stdout);
        printf ("%d", -lit);
        first = false;
      }
      fputc ('\n', stdout);
      tout.normal ();
      fflush (stdout);
    }
#endif
    stats.elimands++;
    stats.elimgates++;

    (void) arity;
    assert (!c->gate);
    c->gate = true;
    eliminator.gates.push_back (c);
    for (const auto & lit : *c) {
      if (lit == -pivot) continue;
      assert (lit != pivot);
      signed char tmp = val (lit);
      if (tmp < 0) continue;
      assert (!tmp);
      assert (marked (lit) < 0);
      marks [vidx (lit)] *= 2;
    }

    unsigned count = 0;
    for (const auto & d : occs (pivot)) {
      if (d->garbage) continue;
      const int other =
        second_literal_in_binary_clause (eliminator, d, pivot);
      if (!other) continue;
      const int tmp = marked (other);
      if (tmp != 2) continue;
      LOG (d, "AND gate binary side clause");
      assert (!d->gate);
      d->gate = true;
      eliminator.gates.push_back (d);
      count++;
    }
    assert (count >= arity);
    (void) count;

    break;
  }

DONE:
  unmark_binary_literals (eliminator);
}

/*------------------------------------------------------------------------*/

// Find and extract ternary clauses.

bool Internal::get_ternary_clause (Clause * d, int & a, int & b, int & c)
{
  if (d->garbage) return false;
  if (d->size < 3) return false;
  int found = 0;
  a = b = c = 0;
  for (const auto & lit : *d) {
    if (val (lit)) continue;
       if (++found == 1) a = lit;
    else if (found == 2) b = lit;
    else if (found == 3) c = lit;
    else return false;
  }
  return found == 3;
}

// This function checks whether 'd' exists as ternary clause.

bool Internal::match_ternary_clause (Clause * d, int a, int b, int c) {
  if (d->garbage) return false;
  int found = 0;
  for (const auto & lit : *d) {
    if (val (lit)) continue;
    if (a != lit && b != lit && c != lit) return false;
    found++;
  }
  return found == 3;
}

Clause *
Internal::find_ternary_clause (int a, int b, int c) {
  if (occs (b).size () > occs (c).size ()) swap (b, c);
  if (occs (a).size () > occs (b).size ()) swap (a, b);
  for (auto d : occs (a))
    if (match_ternary_clause (d, a, b, c))
      return d;
  return 0;
}

/*------------------------------------------------------------------------*/

// Find if-then-else gate.

void Internal::find_if_then_else (Eliminator & eliminator, int pivot) {

  if (!opts.elimites) return;

  assert (opts.elimsubst);

  if (unsat) return;
  if (val (pivot)) return;
  if (!eliminator.gates.empty ()) return;

  const Occs & os = occs (pivot);
  const auto end = os.end ();
  for (auto i = os.begin (); i != end; i++) {
    Clause * di = *i;
    int ai, bi, ci;
    if (!get_ternary_clause (di, ai, bi, ci)) continue;
    if (bi == pivot) swap (ai, bi);
    if (ci == pivot) swap (ai, ci);
    assert (ai == pivot);
    for (auto j = i + 1; j != end; j++) {
      Clause * dj = *j;
      int aj, bj, cj;
      if (!get_ternary_clause (dj, aj, bj, cj)) continue;
      if (bj == pivot) swap (aj, bj);
      if (cj == pivot) swap (aj, cj);
      assert (aj == pivot);
      if (abs (bi) == abs (cj)) swap (bj, cj);
      if (abs (ci) == abs (cj)) continue;
      if (bi != -bj) continue;
      Clause * d1 = find_ternary_clause (-pivot, bi, -ci);
      if (!d1) continue;
      Clause * d2 = find_ternary_clause (-pivot, bj, -cj);
      if (!d2) continue;
      LOG (di, "1st if-then-else");
      LOG (dj, "2nd if-then-else");
      LOG (d1, "3rd if-then-else");
      LOG (d2, "4th if-then-else");
      LOG ("found ITE gate %d == (%d ? %d : %d)", pivot, -bi, -ci, -cj);
      assert (!di->gate);
      assert (!dj->gate);
      assert (!d1->gate);
      assert (!d2->gate);
      di->gate = true;
      dj->gate = true;
      d1->gate = true;
      d2->gate = true;
      eliminator.gates.push_back (di);
      eliminator.gates.push_back (dj);
      eliminator.gates.push_back (d1);
      eliminator.gates.push_back (d2);
      stats.elimgates++;
      stats.elimites++;
      return;
    }
  }
}

/*------------------------------------------------------------------------*/

// Find and extract clause.

bool Internal::get_clause (Clause * c, vector<int> & l) {
  if (c->garbage) return false;
  l.clear ();
  for (const auto & lit : *c) {
    if (val (lit)) continue;
    l.push_back (lit);
  }
  return true;
}

// Check whether 'c' contains only the literals in 'l'.

bool Internal::is_clause (Clause * c, const vector<int> & lits) {
  if (c->garbage) return false;
  int size = lits.size ();
  if (c->size < size) return false;
  int found = 0;
  for (const auto & lit : *c) {
    if (val (lit)) continue;
    const auto it = find (lits.begin (), lits.end (), lit);
    if (it == lits.end ()) return false;
    if (++found > size) return false;
  }
  return found == size;
}

Clause * Internal::find_clause (const vector<int> & lits) {
  int best = 0;
  size_t len = 0;
  for (const auto & lit : lits) {
    size_t l = occs (lit).size ();
    if (best && l >= len) continue;
    len = l, best = lit;
  }
  for (auto c : occs (best))
    if (is_clause (c, lits))
      return c;
  return 0;
}

void Internal::find_xor_gate (Eliminator & eliminator, int pivot) {

  if (!opts.elimxors) return;

  assert (opts.elimsubst);

  if (unsat) return;
  if (val (pivot)) return;
  if (!eliminator.gates.empty ()) return;

  vector<int> lits;

  for (auto d : occs (pivot)) {

    if (!get_clause (d, lits)) continue;

    const int size = lits.size ();      // clause size
    const int arity = size - 1;         // arity of XOR

    if (size < 3) continue;
    if (arity > opts.elimxorlim) continue;

    assert (eliminator.gates.empty ());

    unsigned needed = (1u << arity) - 1;        // additional clauses
    unsigned signs = 0;                         // literals to negate

    do {
      const unsigned prev = signs;
      while (parity (++signs))
        ;
      for (int j = 0; j < size; j++) {
        const unsigned bit = 1u << j;
        int lit = lits[j];
        if ((prev & bit) != (signs & bit))
          lits[j] = lit = -lit;
      }
      Clause * e = find_clause (lits);
      if (!e) break;
      eliminator.gates.push_back (e);
    } while (--needed);

    if (needed) { eliminator.gates.clear (); continue; }

    eliminator.gates.push_back (d);
    assert (eliminator.gates.size () == (1u << arity));

#ifdef LOGGING
    if (opts.log) {
      Logger::print_log_prefix (this);
      tout.magenta ();
      printf ("found arity %u XOR gate %d = ", arity, -pivot);
      bool first = true;
      for (const auto & lit : *d) {
        if (lit == pivot) continue;
        assert (lit != -pivot);
        if (!first) fputs (" ^ ", stdout);
        printf ("%d", lit);
        first = false;
      }
      fputc ('\n', stdout);
      tout.normal ();
      fflush (stdout);
    }
#endif
    stats.elimgates++;
    stats.elimxors++;
    const auto end = eliminator.gates.end ();
    auto j = eliminator.gates.begin ();
    for (auto i = j; i != end; i++) {
      Clause * e = *i;
      if (e->gate) continue;
      e->gate = true;
      LOG (e, "contributing");
      *j++ = e;
    }
    eliminator.gates.resize (j - eliminator.gates.begin ());

    break;
  }
}

/*------------------------------------------------------------------------*/

// Find a gate for 'pivot'.  If such a gate is found, the gate clauses are
// marked and pushed on the stack of gates.  Further hyper unary resolution
// might detect units, which are propagated.  This might assign the pivot or
// even produce the empty clause.

void Internal::find_gate_clauses (Eliminator & eliminator, int pivot)
{
  if (!opts.elimsubst) return;

  if (unsat) return;
  if (val (pivot)) return;

  assert (eliminator.gates.empty ());

  find_equivalence (eliminator, pivot);
  find_and_gate (eliminator, pivot);
  find_and_gate (eliminator, -pivot);
  find_if_then_else (eliminator, pivot);
  find_xor_gate (eliminator, pivot);
}

void Internal::unmark_gate_clauses (Eliminator & eliminator) {
  LOG ("unmarking %zd gate clauses", eliminator.gates.size ());
  for (const auto & c : eliminator.gates) {
    assert (c->gate);
    c->gate = false;
  }
  eliminator.gates.clear ();
}

/*------------------------------------------------------------------------*/

}

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API