/*********************                                                        */
/*! \file sygus_simple_sym.h
 ** \verbatim
 ** Top contributors (to current version):
 **   Andrew Reynolds, Mathias Preiner
 ** This file is part of the CVC4 project.
 ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
 ** in the top-level source directory) and their institutional affiliations.
 ** All rights reserved.  See the file COPYING in the top-level source
 ** directory for licensing information.\endverbatim
 **
 ** \brief Simple symmetry breaking for sygus.
 **/

#include "cvc4_private.h"

#ifndef CVC4__THEORY__DATATYPES__SIMPLE_SYM_BREAK_H
#define CVC4__THEORY__DATATYPES__SIMPLE_SYM_BREAK_H

#include <map>
#include "expr/dtype.h"
#include "theory/quantifiers/sygus/term_database_sygus.h"
#include "theory/quantifiers/term_util.h"

namespace CVC4 {
namespace theory {
namespace datatypes {

/** SygusSimpleSymBreak
 *
 * This class implements queries that can be queried statically about sygus
 * grammars, for example, concerning which constructors need not appear at
 * argument positions of others. This is used by the sygus extension of the
 * quantifier-free datatypes procedure for adding symmetry breaking lemmas.
 * We call this class of techniques "simple static symmetry breaking". These
 * techniques have the advantage over "dynamic symmetry breaking" (blocking
 * redundant solutions on demand in datatypes_sygus.h) in that we can design
 * efficient encodings of symmetry breaking constraints, whereas dynamic
 * symmetry breaking may in the worst case block solutions one by one.
 */
class SygusSimpleSymBreak
{
 public:
  SygusSimpleSymBreak(QuantifiersEngine* qe);
  ~SygusSimpleSymBreak() {}
  /** consider argument kind
   *
   * This method returns false if the arg^th argument of terms of parent kind
   * pk need not be of kind k. The type tnp is the sygus type of type
   * containing pk, and tn is the sygus type of the arg^th argument of the
   * constructor whose builtin kind is pk.
   *
   * For example, given grammar:
   *   A -> A + A | 0 | 1 | x | -A
   * This method will return false for inputs such as:
   *   A, A, -, -, 0  (due to cancelling of double unary minus)
   *   A, A, +, +, 1  (due to commutativity of addition, we can assume all
   *                   nested + occurs in the 0^th argument)
   */
  bool considerArgKind(TypeNode tn, TypeNode tnp, Kind k, Kind pk, int arg);
  /** consider constant
   *
   * Similar to the above function, this method returns false if the arg^th
   * argument of terms of parent kind pk need not be the constant c. The type
   * tnp is the sygus type of type containing pk, and tn is the sygus type of
   * the arg^th argument of the constructor whose builtin kind is pk.
   *
   * For example, given grammar:
   *   A -> B * B | A + A | 0 | 1 | x | -A
   *   B -> 0 | x
   * This method will return false for inputs such as:
   *   A, A, 0, +, 0 (due to identity of addition with zero)
   *   B, A, 0, *, 0 (due to simplification 0*x --> 0, and 0 is generated by A)
   */
  bool considerConst(TypeNode tn, TypeNode tnp, Node c, Kind pk, int arg);
  /** solve for argument
   *
   * If this method returns a non-negative integer n, then all terms at
   * the arg^th position of the cindex^th constructor of sygus type tnp need
   * only be of the n^th constructor of that argument.
   *
   * For example, given grammar:
   *   A -> A - A | A + A | 0 | 1 | x | y
   * Say solveForArgument(A, 0, 0)=2. This indicates that all terms of the form
   * x1-x2 need only be such that x1 is 0.
   */
  int solveForArgument(TypeNode tnp, unsigned cindex, unsigned arg);

 private:
  /** Pointer to the sygus term database */
  quantifiers::TermDbSygus* d_tds;
  /** Pointer to the quantifiers term utility */
  quantifiers::TermUtil* d_tutil;
  /** return the index of the first argument position of c that has type tn */
  int getFirstArgOccurrence(const DTypeConstructor& c, TypeNode tn);
  /**
   * Helper function for consider const above, pdt is the datatype of the type
   * of tnp.
   */
  bool considerConst(const DType& pdt, TypeNode tnp, Node c, Kind pk, int arg);
};

}  // namespace datatypes
}  // namespace theory
}  // namespace CVC4

#endif /* CVC4__THEORY__DATATYPES__SIMPLE_SYM_BREAK_H */
