From: Clark Barrett Date: Thu, 23 Apr 2015 16:43:52 +0000 (-0700) Subject: A few more minor updates to match google repository with CVC4 repository X-Git-Tag: cvc5-1.0.0~6346 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=dea679ce032c130d210d54c2e5482f95db1ff04a;p=cvc5.git A few more minor updates to match google repository with CVC4 repository (mostly whitespace differences). --- diff --git a/config/ax_prog_doxygen.m4 b/config/ax_prog_doxygen.m4 index 2d50f4e6d..3a9744aa9 100644 --- a/config/ax_prog_doxygen.m4 +++ b/config/ax_prog_doxygen.m4 @@ -1,323 +1,323 @@ -# This file is part of Autoconf. -*- Autoconf -*- - -# Renamed doxygen.m4 from acinclude.m4 for inclusion in CVC4 - -# Copyright (C) 2004 Oren Ben-Kiki -# This file is distributed under the same terms as the Autoconf macro files. - -########## CHANGELOG ################## -# 2009-01-14 Martin Mann -# * DX_ARG_ABLE : new variable 'DX_FLAG_DX_CURRENT_FEATURE' -# * DX_CLEAR_DEPEND : use of explicit variable 'DX_FLAG_DX_CURRENT_FEATURE' -# in AC_SUBST instead of 'DX_FLAG[]DX_CURRENT_FEATURE' which is rejected by -# newer autotools - -# Generate automatic documentation using Doxygen. Works in concert with the -# aminclude.m4 file and a compatible doxygen configuration file. Defines the -# following public macros: -# -# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature. -# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics, -# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI' -# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF', -# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment -# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide' -# paper size. -# -# By default, HTML, PDF and PS documentation is generated as this seems to be -# the most popular and portable combination. MAN pages created by Doxygen are -# usually problematic, though by picking an appropriate subset and doing some -# massaging they might be better than nothing. CHM and RTF are specific for MS -# (note that you can't generate both HTML and CHM at the same time). The XML is -# rather useless unless you apply specialized post-processing to it. -# -# The macro mainly controls the default state of the feature. The use can -# override the default by specifying --enable or --disable. The macros ensure -# that contradictory flags are not given (e.g., --enable-doxygen-html and -# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.) -# Finally, each feature will be automatically disabled (with a warning) if the -# required programs are missing. -# -# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with -# the following parameters: a one-word name for the project for use as a -# filename base etc., an optional configuration file name (the default is -# 'Doxyfile', the same as Doxygen's default), and an optional output directory -# name (the default is 'doxygen-doc'). - -## ----------## -## Defaults. ## -## ----------## - -DX_ENV="" -AC_DEFUN([DX_FEATURE_doc], ON) -AC_DEFUN([DX_FEATURE_dot], ON) -AC_DEFUN([DX_FEATURE_man], OFF) -AC_DEFUN([DX_FEATURE_html], ON) -AC_DEFUN([DX_FEATURE_chm], OFF) -AC_DEFUN([DX_FEATURE_chi], OFF) -AC_DEFUN([DX_FEATURE_rtf], OFF) -AC_DEFUN([DX_FEATURE_xml], OFF) -AC_DEFUN([DX_FEATURE_pdf], ON) -AC_DEFUN([DX_FEATURE_ps], ON) - -## --------------- ## -## Private macros. ## -## --------------- ## - -# DX_ENV_APPEND(VARIABLE, VALUE) -# ------------------------------ -# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen. -AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])]) - -# DX_DIRNAME_EXPR -# --------------- -# Expand into a shell expression prints the directory part of a path. -AC_DEFUN([DX_DIRNAME_EXPR], - [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) - -# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) -# ------------------------------------- -# Expands according to the M4 (static) status of the feature. -AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) - -# DX_REQUIRE_PROG(VARIABLE, PROGRAM) -# ---------------------------------- -# Require the specified program to be found for the DX_CURRENT_FEATURE to work. -AC_DEFUN([DX_REQUIRE_PROG], [ -AC_PATH_TOOL([$1], [$2]) -if test "$DX_FLAG_DX_CURRENT_FEATURE$$1" = 1; then - AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) - AC_SUBST([DX_FLAG_DX_CURRENT_FEATURE], 0) -fi -]) - -# DX_TEST_FEATURE(FEATURE) -# ------------------------ -# Expand to a shell expression testing whether the feature is active. -AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) - -# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) -# ------------------------------------------------- -# Verify that a required features has the right state before trying to turn on -# the DX_CURRENT_FEATURE. -AC_DEFUN([DX_CHECK_DEPEND], [ -test "$DX_FLAG_$1" = "$2" \ -|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, - requires, contradicts) doxygen-DX_CURRENT_FEATURE]) -]) - -# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) -# ---------------------------------------------------------- -# Turn off the DX_CURRENT_FEATURE if the required feature is off. -AC_DEFUN([DX_CLEAR_DEPEND], [ -test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_DX_CURRENT_FEATURE], 0) -]) - - -# DX_FEATURE_ARG(FEATURE, DESCRIPTION, -# CHECK_DEPEND, CLEAR_DEPEND, -# REQUIRE, DO-IF-ON, DO-IF-OFF) -# -------------------------------------------- -# Parse the command-line option controlling a feature. CHECK_DEPEND is called -# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), -# otherwise CLEAR_DEPEND is called to turn off the default state if a required -# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional -# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and -# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. -AC_DEFUN([DX_ARG_ABLE], [ - AC_DEFUN([DX_CURRENT_FEATURE], [$1]) - AC_DEFUN([DX_FLAG_DX_CURRENT_FEATURE], [DX_FLAG_$1]) - AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) - AC_ARG_ENABLE(doxygen-$1, - [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], - [--enable-doxygen-$1]), - DX_IF_FEATURE([$1], [don't $2], [$2]))], - [ -case "$enableval" in -#( -y|Y|yes|Yes|YES) - AC_SUBST([DX_FLAG_$1], 1) - $3 -;; #( -n|N|no|No|NO) - AC_SUBST([DX_FLAG_$1], 0) -;; #( -*) - AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) -;; -esac -], [ -AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) -$4 -]) -if DX_TEST_FEATURE([$1]); then - $5 - : -fi -if DX_TEST_FEATURE([$1]); then - AM_CONDITIONAL(DX_COND_$1, :) - $6 - : -else - AM_CONDITIONAL(DX_COND_$1, false) - $7 - : -fi -]) - -## -------------- ## -## Public macros. ## -## -------------- ## - -# DX_XXX_FEATURE(DEFAULT_STATE) -# ----------------------------- -AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) -AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) -AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) -AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) -AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) -AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) -AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) -AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])]) -AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) -AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) - -# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR]) -# --------------------------------------------------------- -# PROJECT also serves as the base name for the documentation files. -# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc". -AC_DEFUN([DX_INIT_DOXYGEN], [ - -# Files: -AC_SUBST([DX_PROJECT], [$1]) -AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])]) -AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])]) - -# Environment variables used inside doxygen.cfg: -DX_ENV_APPEND(SRCDIR, $srcdir) -DX_ENV_APPEND(PROJECT, $DX_PROJECT) -DX_ENV_APPEND(DOCDIR, $DX_DOCDIR) -DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) - -# Doxygen itself: -DX_ARG_ABLE(doc, [generate any doxygen documentation], - [], - [], - [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) - DX_REQUIRE_PROG([DX_PERL], perl)], - [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) - -# Dot for graphics: -DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [DX_REQUIRE_PROG([DX_DOT], dot)], - [DX_ENV_APPEND(HAVE_DOT, YES) - DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], - [DX_ENV_APPEND(HAVE_DOT, NO)]) - -# Man pages generation: -DX_ARG_ABLE(man, [generate doxygen manual pages], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [], - [DX_ENV_APPEND(GENERATE_MAN, YES)], - [DX_ENV_APPEND(GENERATE_MAN, NO)]) - -# RTF file generation: -DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [], - [DX_ENV_APPEND(GENERATE_RTF, YES)], - [DX_ENV_APPEND(GENERATE_RTF, NO)]) - -# XML file generation: -DX_ARG_ABLE(xml, [generate doxygen XML documentation], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [], - [DX_ENV_APPEND(GENERATE_XML, YES)], - [DX_ENV_APPEND(GENERATE_XML, NO)]) - -# (Compressed) HTML help generation: -DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [DX_REQUIRE_PROG([DX_HHC], hhc)], - [DX_ENV_APPEND(HHC_PATH, $DX_HHC) - DX_ENV_APPEND(GENERATE_HTML, YES) - DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], - [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) - -# Seperate CHI file generation. -DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file], - [DX_CHECK_DEPEND(chm, 1)], - [DX_CLEAR_DEPEND(chm, 1)], - [], - [DX_ENV_APPEND(GENERATE_CHI, YES)], - [DX_ENV_APPEND(GENERATE_CHI, NO)]) - -# Plain HTML pages generation: -DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], - [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], - [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], - [], - [DX_ENV_APPEND(GENERATE_HTML, YES)], - [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) - -# PostScript file generation: -DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [DX_REQUIRE_PROG([DX_LATEX], latex) - DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) - DX_REQUIRE_PROG([DX_DVIPS], dvips) - DX_REQUIRE_PROG([DX_EGREP], egrep)]) - -# PDF file generation: -DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], - [DX_CHECK_DEPEND(doc, 1)], - [DX_CLEAR_DEPEND(doc, 1)], - [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) - DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) - DX_REQUIRE_PROG([DX_EGREP], egrep)]) - -# LaTeX generation for PS and/or PDF: -if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then - AM_CONDITIONAL(DX_COND_latex, :) - DX_ENV_APPEND(GENERATE_LATEX, YES) -else - AM_CONDITIONAL(DX_COND_latex, false) - DX_ENV_APPEND(GENERATE_LATEX, NO) -fi - -# Paper size for PS and/or PDF: -AC_ARG_VAR(DOXYGEN_PAPER_SIZE, - [a4wide (default), a4, letter, legal or executive]) -case "$DOXYGEN_PAPER_SIZE" in -#( -"") - AC_SUBST(DOXYGEN_PAPER_SIZE, "") -;; #( -a4wide|a4|letter|legal|executive) - DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) -;; #( -*) - AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) -;; -esac - -#For debugging: -#echo DX_FLAG_doc=$DX_FLAG_doc -#echo DX_FLAG_dot=$DX_FLAG_dot -#echo DX_FLAG_man=$DX_FLAG_man -#echo DX_FLAG_html=$DX_FLAG_html -#echo DX_FLAG_chm=$DX_FLAG_chm -#echo DX_FLAG_chi=$DX_FLAG_chi -#echo DX_FLAG_rtf=$DX_FLAG_rtf -#echo DX_FLAG_xml=$DX_FLAG_xml -#echo DX_FLAG_pdf=$DX_FLAG_pdf -#echo DX_FLAG_ps=$DX_FLAG_ps -#echo DX_ENV=$DX_ENV -]) +# This file is part of Autoconf. -*- Autoconf -*- + +# Renamed doxygen.m4 from acinclude.m4 for inclusion in CVC4 + +# Copyright (C) 2004 Oren Ben-Kiki +# This file is distributed under the same terms as the Autoconf macro files. + +########## CHANGELOG ################## +# 2009-01-14 Martin Mann +# * DX_ARG_ABLE : new variable 'DX_FLAG_DX_CURRENT_FEATURE' +# * DX_CLEAR_DEPEND : use of explicit variable 'DX_FLAG_DX_CURRENT_FEATURE' +# in AC_SUBST instead of 'DX_FLAG[]DX_CURRENT_FEATURE' which is rejected by +# newer autotools + +# Generate automatic documentation using Doxygen. Works in concert with the +# aminclude.m4 file and a compatible doxygen configuration file. Defines the +# following public macros: +# +# DX_???_FEATURE(ON|OFF) - control the default setting fo a Doxygen feature. +# Supported features are 'DOXYGEN' itself, 'DOT' for generating graphics, +# 'HTML' for plain HTML, 'CHM' for compressed HTML help (for MS users), 'CHI' +# for generating a seperate .chi file by the .chm file, and 'MAN', 'RTF', +# 'XML', 'PDF' and 'PS' for the appropriate output formats. The environment +# variable DOXYGEN_PAPER_SIZE may be specified to override the default 'a4wide' +# paper size. +# +# By default, HTML, PDF and PS documentation is generated as this seems to be +# the most popular and portable combination. MAN pages created by Doxygen are +# usually problematic, though by picking an appropriate subset and doing some +# massaging they might be better than nothing. CHM and RTF are specific for MS +# (note that you can't generate both HTML and CHM at the same time). The XML is +# rather useless unless you apply specialized post-processing to it. +# +# The macro mainly controls the default state of the feature. The use can +# override the default by specifying --enable or --disable. The macros ensure +# that contradictory flags are not given (e.g., --enable-doxygen-html and +# --enable-doxygen-chm, --enable-doxygen-anything with --disable-doxygen, etc.) +# Finally, each feature will be automatically disabled (with a warning) if the +# required programs are missing. +# +# Once all the feature defaults have been specified, call DX_INIT_DOXYGEN with +# the following parameters: a one-word name for the project for use as a +# filename base etc., an optional configuration file name (the default is +# 'Doxyfile', the same as Doxygen's default), and an optional output directory +# name (the default is 'doxygen-doc'). + +## ----------## +## Defaults. ## +## ----------## + +DX_ENV="" +AC_DEFUN([DX_FEATURE_doc], ON) +AC_DEFUN([DX_FEATURE_dot], ON) +AC_DEFUN([DX_FEATURE_man], OFF) +AC_DEFUN([DX_FEATURE_html], ON) +AC_DEFUN([DX_FEATURE_chm], OFF) +AC_DEFUN([DX_FEATURE_chi], OFF) +AC_DEFUN([DX_FEATURE_rtf], OFF) +AC_DEFUN([DX_FEATURE_xml], OFF) +AC_DEFUN([DX_FEATURE_pdf], ON) +AC_DEFUN([DX_FEATURE_ps], ON) + +## --------------- ## +## Private macros. ## +## --------------- ## + +# DX_ENV_APPEND(VARIABLE, VALUE) +# ------------------------------ +# Append VARIABLE="VALUE" to DX_ENV for invoking doxygen. +AC_DEFUN([DX_ENV_APPEND], [AC_SUBST([DX_ENV], ["$DX_ENV $1='$2'"])]) + +# DX_DIRNAME_EXPR +# --------------- +# Expand into a shell expression prints the directory part of a path. +AC_DEFUN([DX_DIRNAME_EXPR], + [[expr ".$1" : '\(\.\)[^/]*$' \| "x$1" : 'x\(.*\)/[^/]*$']]) + +# DX_IF_FEATURE(FEATURE, IF-ON, IF-OFF) +# ------------------------------------- +# Expands according to the M4 (static) status of the feature. +AC_DEFUN([DX_IF_FEATURE], [ifelse(DX_FEATURE_$1, ON, [$2], [$3])]) + +# DX_REQUIRE_PROG(VARIABLE, PROGRAM) +# ---------------------------------- +# Require the specified program to be found for the DX_CURRENT_FEATURE to work. +AC_DEFUN([DX_REQUIRE_PROG], [ +AC_PATH_TOOL([$1], [$2]) +if test "$DX_FLAG_DX_CURRENT_FEATURE$$1" = 1; then + AC_MSG_WARN([$2 not found - will not DX_CURRENT_DESCRIPTION]) + AC_SUBST([DX_FLAG_DX_CURRENT_FEATURE], 0) +fi +]) + +# DX_TEST_FEATURE(FEATURE) +# ------------------------ +# Expand to a shell expression testing whether the feature is active. +AC_DEFUN([DX_TEST_FEATURE], [test "$DX_FLAG_$1" = 1]) + +# DX_CHECK_DEPEND(REQUIRED_FEATURE, REQUIRED_STATE) +# ------------------------------------------------- +# Verify that a required features has the right state before trying to turn on +# the DX_CURRENT_FEATURE. +AC_DEFUN([DX_CHECK_DEPEND], [ +test "$DX_FLAG_$1" = "$2" \ +|| AC_MSG_ERROR([doxygen-DX_CURRENT_FEATURE ifelse([$2], 1, + requires, contradicts) doxygen-DX_CURRENT_FEATURE]) +]) + +# DX_CLEAR_DEPEND(FEATURE, REQUIRED_FEATURE, REQUIRED_STATE) +# ---------------------------------------------------------- +# Turn off the DX_CURRENT_FEATURE if the required feature is off. +AC_DEFUN([DX_CLEAR_DEPEND], [ +test "$DX_FLAG_$1" = "$2" || AC_SUBST([DX_FLAG_DX_CURRENT_FEATURE], 0) +]) + + +# DX_FEATURE_ARG(FEATURE, DESCRIPTION, +# CHECK_DEPEND, CLEAR_DEPEND, +# REQUIRE, DO-IF-ON, DO-IF-OFF) +# -------------------------------------------- +# Parse the command-line option controlling a feature. CHECK_DEPEND is called +# if the user explicitly turns the feature on (and invokes DX_CHECK_DEPEND), +# otherwise CLEAR_DEPEND is called to turn off the default state if a required +# feature is disabled (using DX_CLEAR_DEPEND). REQUIRE performs additional +# requirement tests (DX_REQUIRE_PROG). Finally, an automake flag is set and +# DO-IF-ON or DO-IF-OFF are called according to the final state of the feature. +AC_DEFUN([DX_ARG_ABLE], [ + AC_DEFUN([DX_CURRENT_FEATURE], [$1]) + AC_DEFUN([DX_FLAG_DX_CURRENT_FEATURE], [DX_FLAG_$1]) + AC_DEFUN([DX_CURRENT_DESCRIPTION], [$2]) + AC_ARG_ENABLE(doxygen-$1, + [AS_HELP_STRING(DX_IF_FEATURE([$1], [--disable-doxygen-$1], + [--enable-doxygen-$1]), + DX_IF_FEATURE([$1], [don't $2], [$2]))], + [ +case "$enableval" in +#( +y|Y|yes|Yes|YES) + AC_SUBST([DX_FLAG_$1], 1) + $3 +;; #( +n|N|no|No|NO) + AC_SUBST([DX_FLAG_$1], 0) +;; #( +*) + AC_MSG_ERROR([invalid value '$enableval' given to doxygen-$1]) +;; +esac +], [ +AC_SUBST([DX_FLAG_$1], [DX_IF_FEATURE([$1], 1, 0)]) +$4 +]) +if DX_TEST_FEATURE([$1]); then + $5 + : +fi +if DX_TEST_FEATURE([$1]); then + AM_CONDITIONAL(DX_COND_$1, :) + $6 + : +else + AM_CONDITIONAL(DX_COND_$1, false) + $7 + : +fi +]) + +## -------------- ## +## Public macros. ## +## -------------- ## + +# DX_XXX_FEATURE(DEFAULT_STATE) +# ----------------------------- +AC_DEFUN([DX_DOXYGEN_FEATURE], [AC_DEFUN([DX_FEATURE_doc], [$1])]) +AC_DEFUN([DX_MAN_FEATURE], [AC_DEFUN([DX_FEATURE_man], [$1])]) +AC_DEFUN([DX_HTML_FEATURE], [AC_DEFUN([DX_FEATURE_html], [$1])]) +AC_DEFUN([DX_CHM_FEATURE], [AC_DEFUN([DX_FEATURE_chm], [$1])]) +AC_DEFUN([DX_CHI_FEATURE], [AC_DEFUN([DX_FEATURE_chi], [$1])]) +AC_DEFUN([DX_RTF_FEATURE], [AC_DEFUN([DX_FEATURE_rtf], [$1])]) +AC_DEFUN([DX_XML_FEATURE], [AC_DEFUN([DX_FEATURE_xml], [$1])]) +AC_DEFUN([DX_DOT_FEATURE], [AC_DEFUN([DX_FEATURE_dot], [$1])]) +AC_DEFUN([DX_PDF_FEATURE], [AC_DEFUN([DX_FEATURE_pdf], [$1])]) +AC_DEFUN([DX_PS_FEATURE], [AC_DEFUN([DX_FEATURE_ps], [$1])]) + +# DX_INIT_DOXYGEN(PROJECT, [CONFIG-FILE], [OUTPUT-DOC-DIR]) +# --------------------------------------------------------- +# PROJECT also serves as the base name for the documentation files. +# The default CONFIG-FILE is "Doxyfile" and OUTPUT-DOC-DIR is "doxygen-doc". +AC_DEFUN([DX_INIT_DOXYGEN], [ + +# Files: +AC_SUBST([DX_PROJECT], [$1]) +AC_SUBST([DX_CONFIG], [ifelse([$2], [], Doxyfile, [$2])]) +AC_SUBST([DX_DOCDIR], [ifelse([$3], [], doxygen-doc, [$3])]) + +# Environment variables used inside doxygen.cfg: +DX_ENV_APPEND(SRCDIR, $srcdir) +DX_ENV_APPEND(PROJECT, $DX_PROJECT) +DX_ENV_APPEND(DOCDIR, $DX_DOCDIR) +DX_ENV_APPEND(VERSION, $PACKAGE_VERSION) + +# Doxygen itself: +DX_ARG_ABLE(doc, [generate any doxygen documentation], + [], + [], + [DX_REQUIRE_PROG([DX_DOXYGEN], doxygen) + DX_REQUIRE_PROG([DX_PERL], perl)], + [DX_ENV_APPEND(PERL_PATH, $DX_PERL)]) + +# Dot for graphics: +DX_ARG_ABLE(dot, [generate graphics for doxygen documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_DOT], dot)], + [DX_ENV_APPEND(HAVE_DOT, YES) + DX_ENV_APPEND(DOT_PATH, [`DX_DIRNAME_EXPR($DX_DOT)`])], + [DX_ENV_APPEND(HAVE_DOT, NO)]) + +# Man pages generation: +DX_ARG_ABLE(man, [generate doxygen manual pages], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [], + [DX_ENV_APPEND(GENERATE_MAN, YES)], + [DX_ENV_APPEND(GENERATE_MAN, NO)]) + +# RTF file generation: +DX_ARG_ABLE(rtf, [generate doxygen RTF documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [], + [DX_ENV_APPEND(GENERATE_RTF, YES)], + [DX_ENV_APPEND(GENERATE_RTF, NO)]) + +# XML file generation: +DX_ARG_ABLE(xml, [generate doxygen XML documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [], + [DX_ENV_APPEND(GENERATE_XML, YES)], + [DX_ENV_APPEND(GENERATE_XML, NO)]) + +# (Compressed) HTML help generation: +DX_ARG_ABLE(chm, [generate doxygen compressed HTML help documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_HHC], hhc)], + [DX_ENV_APPEND(HHC_PATH, $DX_HHC) + DX_ENV_APPEND(GENERATE_HTML, YES) + DX_ENV_APPEND(GENERATE_HTMLHELP, YES)], + [DX_ENV_APPEND(GENERATE_HTMLHELP, NO)]) + +# Seperate CHI file generation. +DX_ARG_ABLE(chi, [generate doxygen seperate compressed HTML help index file], + [DX_CHECK_DEPEND(chm, 1)], + [DX_CLEAR_DEPEND(chm, 1)], + [], + [DX_ENV_APPEND(GENERATE_CHI, YES)], + [DX_ENV_APPEND(GENERATE_CHI, NO)]) + +# Plain HTML pages generation: +DX_ARG_ABLE(html, [generate doxygen plain HTML documentation], + [DX_CHECK_DEPEND(doc, 1) DX_CHECK_DEPEND(chm, 0)], + [DX_CLEAR_DEPEND(doc, 1) DX_CLEAR_DEPEND(chm, 0)], + [], + [DX_ENV_APPEND(GENERATE_HTML, YES)], + [DX_TEST_FEATURE(chm) || DX_ENV_APPEND(GENERATE_HTML, NO)]) + +# PostScript file generation: +DX_ARG_ABLE(ps, [generate doxygen PostScript documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_LATEX], latex) + DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) + DX_REQUIRE_PROG([DX_DVIPS], dvips) + DX_REQUIRE_PROG([DX_EGREP], egrep)]) + +# PDF file generation: +DX_ARG_ABLE(pdf, [generate doxygen PDF documentation], + [DX_CHECK_DEPEND(doc, 1)], + [DX_CLEAR_DEPEND(doc, 1)], + [DX_REQUIRE_PROG([DX_PDFLATEX], pdflatex) + DX_REQUIRE_PROG([DX_MAKEINDEX], makeindex) + DX_REQUIRE_PROG([DX_EGREP], egrep)]) + +# LaTeX generation for PS and/or PDF: +if DX_TEST_FEATURE(ps) || DX_TEST_FEATURE(pdf); then + AM_CONDITIONAL(DX_COND_latex, :) + DX_ENV_APPEND(GENERATE_LATEX, YES) +else + AM_CONDITIONAL(DX_COND_latex, false) + DX_ENV_APPEND(GENERATE_LATEX, NO) +fi + +# Paper size for PS and/or PDF: +AC_ARG_VAR(DOXYGEN_PAPER_SIZE, + [a4wide (default), a4, letter, legal or executive]) +case "$DOXYGEN_PAPER_SIZE" in +#( +"") + AC_SUBST(DOXYGEN_PAPER_SIZE, "") +;; #( +a4wide|a4|letter|legal|executive) + DX_ENV_APPEND(PAPER_SIZE, $DOXYGEN_PAPER_SIZE) +;; #( +*) + AC_MSG_ERROR([unknown DOXYGEN_PAPER_SIZE='$DOXYGEN_PAPER_SIZE']) +;; +esac + +#For debugging: +#echo DX_FLAG_doc=$DX_FLAG_doc +#echo DX_FLAG_dot=$DX_FLAG_dot +#echo DX_FLAG_man=$DX_FLAG_man +#echo DX_FLAG_html=$DX_FLAG_html +#echo DX_FLAG_chm=$DX_FLAG_chm +#echo DX_FLAG_chi=$DX_FLAG_chi +#echo DX_FLAG_rtf=$DX_FLAG_rtf +#echo DX_FLAG_xml=$DX_FLAG_xml +#echo DX_FLAG_pdf=$DX_FLAG_pdf +#echo DX_FLAG_ps=$DX_FLAG_ps +#echo DX_ENV=$DX_ENV +]) diff --git a/examples/api/java/Strings.java b/examples/api/java/Strings.java index 9437115a9..bb9dcd822 100644 --- a/examples/api/java/Strings.java +++ b/examples/api/java/Strings.java @@ -1,91 +1,91 @@ -/********************* */ -/*! \file Strings.java - ** \verbatim - ** Original author: Tianyi Liang - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Reasoning about strings with CVC4 via Java API. - ** - ** A simple demonstration of reasoning about strings with CVC4 via Jave API. - **/ - -import edu.nyu.acsys.CVC4.*; - -public class Strings { - public static void main(String[] args) { - System.loadLibrary("cvc4jni"); - - ExprManager em = new ExprManager(); - SmtEngine smt = new SmtEngine(em); - - // Set the logic - smt.setLogic("S"); - - // Produce models - smt.setOption("produce-models", new SExpr(true)); - // The option strings-exp is needed - smt.setOption("strings-exp", new SExpr(true)); - // output-language - smt.setOption("output-language", new SExpr("smt2")); - - // String type - Type string = em.stringType(); - - // String constants - Expr ab = em.mkConst(new CVC4String("ab")); - Expr abc = em.mkConst(new CVC4String("abc")); - // Variables - Expr x = em.mkVar("x", string); - Expr y = em.mkVar("y", string); - Expr z = em.mkVar("z", string); - - // String concatenation: x.ab.y - Expr lhs = em.mkExpr(Kind.STRING_CONCAT, x, ab, y); - // String concatenation: abc.z - Expr rhs = em.mkExpr(Kind.STRING_CONCAT, abc, z);; - // x.ab.y = abc.z - Expr formula1 = em.mkExpr(Kind.EQUAL, lhs, rhs); - - // Length of y: |y| - Expr leny = em.mkExpr(Kind.STRING_LENGTH, y); - // |y| >= 0 - Expr formula2 = em.mkExpr(Kind.GEQ, leny, em.mkConst(new Rational(0))); - - // Regular expression: (ab[c-e]*f)|g|h - Expr r = em.mkExpr(Kind.REGEXP_UNION, - em.mkExpr(Kind.REGEXP_CONCAT, - em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("ab"))), - em.mkExpr(Kind.REGEXP_STAR, - em.mkExpr(Kind.REGEXP_RANGE, em.mkConst(new CVC4String("c")), em.mkConst(new CVC4String("e")))), - em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("f")))), - em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("g"))), - em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("h")))); - - // String variables - Expr s1 = em.mkVar("s1", string); - Expr s2 = em.mkVar("s2", string); - // String concatenation: s1.s2 - Expr s = em.mkExpr(Kind.STRING_CONCAT, s1, s2); - - // s1.s2 in (ab[c-e]*f)|g|h - Expr formula3 = em.mkExpr(Kind.STRING_IN_REGEXP, s, r); - - // Make a query - Expr q = em.mkExpr(Kind.AND, - formula1, - formula2, - formula3); - - // check sat - Result result = smt.checkSat(q); - System.out.println("CVC4 reports: " + q + " is " + result + "."); - - System.out.println(" x = " + smt.getValue(x)); - System.out.println(" s1.s2 = " + smt.getValue(s)); - } -} +/********************* */ +/*! \file Strings.java + ** \verbatim + ** Original author: Tianyi Liang + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2014 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Reasoning about strings with CVC4 via Java API. + ** + ** A simple demonstration of reasoning about strings with CVC4 via Jave API. + **/ + +import edu.nyu.acsys.CVC4.*; + +public class Strings { + public static void main(String[] args) { + System.loadLibrary("cvc4jni"); + + ExprManager em = new ExprManager(); + SmtEngine smt = new SmtEngine(em); + + // Set the logic + smt.setLogic("S"); + + // Produce models + smt.setOption("produce-models", new SExpr(true)); + // The option strings-exp is needed + smt.setOption("strings-exp", new SExpr(true)); + // output-language + smt.setOption("output-language", new SExpr("smt2")); + + // String type + Type string = em.stringType(); + + // String constants + Expr ab = em.mkConst(new CVC4String("ab")); + Expr abc = em.mkConst(new CVC4String("abc")); + // Variables + Expr x = em.mkVar("x", string); + Expr y = em.mkVar("y", string); + Expr z = em.mkVar("z", string); + + // String concatenation: x.ab.y + Expr lhs = em.mkExpr(Kind.STRING_CONCAT, x, ab, y); + // String concatenation: abc.z + Expr rhs = em.mkExpr(Kind.STRING_CONCAT, abc, z);; + // x.ab.y = abc.z + Expr formula1 = em.mkExpr(Kind.EQUAL, lhs, rhs); + + // Length of y: |y| + Expr leny = em.mkExpr(Kind.STRING_LENGTH, y); + // |y| >= 0 + Expr formula2 = em.mkExpr(Kind.GEQ, leny, em.mkConst(new Rational(0))); + + // Regular expression: (ab[c-e]*f)|g|h + Expr r = em.mkExpr(Kind.REGEXP_UNION, + em.mkExpr(Kind.REGEXP_CONCAT, + em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("ab"))), + em.mkExpr(Kind.REGEXP_STAR, + em.mkExpr(Kind.REGEXP_RANGE, em.mkConst(new CVC4String("c")), em.mkConst(new CVC4String("e")))), + em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("f")))), + em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("g"))), + em.mkExpr(Kind.STRING_TO_REGEXP, em.mkConst(new CVC4String("h")))); + + // String variables + Expr s1 = em.mkVar("s1", string); + Expr s2 = em.mkVar("s2", string); + // String concatenation: s1.s2 + Expr s = em.mkExpr(Kind.STRING_CONCAT, s1, s2); + + // s1.s2 in (ab[c-e]*f)|g|h + Expr formula3 = em.mkExpr(Kind.STRING_IN_REGEXP, s, r); + + // Make a query + Expr q = em.mkExpr(Kind.AND, + formula1, + formula2, + formula3); + + // check sat + Result result = smt.checkSat(q); + System.out.println("CVC4 reports: " + q + " is " + result + "."); + + System.out.println(" x = " + smt.getValue(x)); + System.out.println(" s1.s2 = " + smt.getValue(s)); + } +} diff --git a/examples/api/strings.cpp b/examples/api/strings.cpp index a424c654a..14ab0e64d 100644 --- a/examples/api/strings.cpp +++ b/examples/api/strings.cpp @@ -1,101 +1,101 @@ -/********************* */ -/*! \file sets.cpp - ** \verbatim - ** Original author: Tianyi Liang - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Reasoning about strings with CVC4 via C++ API. - ** - ** A simple demonstration of reasoning about strings with CVC4 via C++ API. - **/ - -#include - -//#include // use this after CVC4 is properly installed -#include "smt/smt_engine.h" - -using namespace CVC4; - -int main() { - ExprManager em; - SmtEngine smt(&em); - - // Set the logic - smt.setLogic("S"); - - // Produce models - smt.setOption("produce-models", true); - - // The option strings-exp is needed - smt.setOption("strings-exp", true); - - // Set output language to SMTLIB2 - std::cout << Expr::setlanguage(language::output::LANG_SMTLIB_V2); - - // String type - Type string = em.stringType(); - - // std::string - std::string std_str_ab("ab"); - // CVC4::String - CVC4::String cvc4_str_ab(std_str_ab); - CVC4::String cvc4_str_abc("abc"); - // String constants - Expr ab = em.mkConst(cvc4_str_ab); - Expr abc = em.mkConst(CVC4::String("abc")); - // String variables - Expr x = em.mkVar("x", string); - Expr y = em.mkVar("y", string); - Expr z = em.mkVar("z", string); - - // String concatenation: x.ab.y - Expr lhs = em.mkExpr(kind::STRING_CONCAT, x, ab, y); - // String concatenation: abc.z - Expr rhs = em.mkExpr(kind::STRING_CONCAT, abc, z); - // x.ab.y = abc.z - Expr formula1 = em.mkExpr(kind::EQUAL, lhs, rhs); - - // Length of y: |y| - Expr leny = em.mkExpr(kind::STRING_LENGTH, y); - // |y| >= 0 - Expr formula2 = em.mkExpr(kind::GEQ, leny, em.mkConst(Rational(0))); - - // Regular expression: (ab[c-e]*f)|g|h - Expr r = em.mkExpr(kind::REGEXP_UNION, - em.mkExpr(kind::REGEXP_CONCAT, - em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("ab"))), - em.mkExpr(kind::REGEXP_STAR, - em.mkExpr(kind::REGEXP_RANGE, em.mkConst(String("c")), em.mkConst(String("e")))), - em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("f")))), - em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("g"))), - em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("h")))); - - // String variables - Expr s1 = em.mkVar("s1", string); - Expr s2 = em.mkVar("s2", string); - // String concatenation: s1.s2 - Expr s = em.mkExpr(kind::STRING_CONCAT, s1, s2); - - // s1.s2 in (ab[c-e]*f)|g|h - Expr formula3 = em.mkExpr(kind::STRING_IN_REGEXP, s, r); - - // Make a query - Expr q = em.mkExpr(kind::AND, - formula1, - formula2, - formula3); - - // check sat - Result result = smt.checkSat(q); - std::cout << "CVC4 reports: " << q << " is " << result << "." << std::endl; - - if(result == Result::SAT) { - std::cout << " x = " << smt.getValue(x) << std::endl; - std::cout << " s1.s2 = " << smt.getValue(s) << std::endl; - } -} +/********************* */ +/*! \file sets.cpp + ** \verbatim + ** Original author: Tianyi Liang + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2014 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Reasoning about strings with CVC4 via C++ API. + ** + ** A simple demonstration of reasoning about strings with CVC4 via C++ API. + **/ + +#include + +//#include // use this after CVC4 is properly installed +#include "smt/smt_engine.h" + +using namespace CVC4; + +int main() { + ExprManager em; + SmtEngine smt(&em); + + // Set the logic + smt.setLogic("S"); + + // Produce models + smt.setOption("produce-models", true); + + // The option strings-exp is needed + smt.setOption("strings-exp", true); + + // Set output language to SMTLIB2 + std::cout << Expr::setlanguage(language::output::LANG_SMTLIB_V2); + + // String type + Type string = em.stringType(); + + // std::string + std::string std_str_ab("ab"); + // CVC4::String + CVC4::String cvc4_str_ab(std_str_ab); + CVC4::String cvc4_str_abc("abc"); + // String constants + Expr ab = em.mkConst(cvc4_str_ab); + Expr abc = em.mkConst(CVC4::String("abc")); + // String variables + Expr x = em.mkVar("x", string); + Expr y = em.mkVar("y", string); + Expr z = em.mkVar("z", string); + + // String concatenation: x.ab.y + Expr lhs = em.mkExpr(kind::STRING_CONCAT, x, ab, y); + // String concatenation: abc.z + Expr rhs = em.mkExpr(kind::STRING_CONCAT, abc, z); + // x.ab.y = abc.z + Expr formula1 = em.mkExpr(kind::EQUAL, lhs, rhs); + + // Length of y: |y| + Expr leny = em.mkExpr(kind::STRING_LENGTH, y); + // |y| >= 0 + Expr formula2 = em.mkExpr(kind::GEQ, leny, em.mkConst(Rational(0))); + + // Regular expression: (ab[c-e]*f)|g|h + Expr r = em.mkExpr(kind::REGEXP_UNION, + em.mkExpr(kind::REGEXP_CONCAT, + em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("ab"))), + em.mkExpr(kind::REGEXP_STAR, + em.mkExpr(kind::REGEXP_RANGE, em.mkConst(String("c")), em.mkConst(String("e")))), + em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("f")))), + em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("g"))), + em.mkExpr(kind::STRING_TO_REGEXP, em.mkConst(String("h")))); + + // String variables + Expr s1 = em.mkVar("s1", string); + Expr s2 = em.mkVar("s2", string); + // String concatenation: s1.s2 + Expr s = em.mkExpr(kind::STRING_CONCAT, s1, s2); + + // s1.s2 in (ab[c-e]*f)|g|h + Expr formula3 = em.mkExpr(kind::STRING_IN_REGEXP, s, r); + + // Make a query + Expr q = em.mkExpr(kind::AND, + formula1, + formula2, + formula3); + + // check sat + Result result = smt.checkSat(q); + std::cout << "CVC4 reports: " << q << " is " << result << "." << std::endl; + + if(result == Result::SAT) { + std::cout << " x = " << smt.getValue(x) << std::endl; + std::cout << " s1.s2 = " << smt.getValue(s) << std::endl; + } +} diff --git a/proofs/lfsc_checker/libwriter.cpp b/proofs/lfsc_checker/libwriter.cpp index 49e9bbaad..016016c9d 100644 --- a/proofs/lfsc_checker/libwriter.cpp +++ b/proofs/lfsc_checker/libwriter.cpp @@ -1,238 +1,238 @@ -#include "libwriter.h" -#include -#include -#include - -void libwriter::get_var_name( const std::string& n, std::string& nn ) { - nn = std::string( n.c_str() ); - for( int i = 0; i <(int)n.length(); i++ ){ - char c = n[i]; - if (c <= 47) - c += 65; - else if (c >= 58 && c <= 64) - c += 97-58; - if ((c >= 91 && c <= 94) || c == 96) - c += 104-91; - else if (c >= 123) - c -= 4; - nn[i] = c; - } -} - -void libwriter::write_file() -{ - //std::cout << "write lib" << std::endl; - std::ostringstream os_enum; - std::ostringstream os_print; - std::ostringstream os_constructor_h; - std::ostringstream os_constructor_c; - - for ( int a=0; a<(int)syms.size(); a++ ) { - //std::cout << "sym #" << (a+1) << ": "; - //std::cout << ((SymSExpr*)syms[a])->s.c_str() << std::endl; - //defs[a]->print( std::cout ); - //std::cout << std::endl; - - if( defs[a]->getclass()==CEXPR ){ - //calculate which arguments are required for input - std::vector< Expr* > args; - std::vector< bool > argsNeed; - std::vector< Expr* > argTypes; - CExpr* c = ((CExpr*)defs[a]); - while( c->getop()==PI ){ - //std::cout << c->kids[0] << std::endl; - if( ((CExpr*)c->kids[1])->getop()!=RUN ){ - args.push_back( c->kids[0] ); - argsNeed.push_back( true ); - argTypes.push_back( c->kids[1] ); - } - for( int b=0; b<(int)args.size(); b++ ){ - if( argsNeed[b] ){ - if( ((CExpr*)c->kids[1])->getop()==RUN ){ - if( ((CExpr*)c->kids[1])->kids[1]->free_in( args[b] ) ){ - argsNeed[b] = false; - } - }else{ - if( c->kids[1]->free_in( args[b] ) ){ - argsNeed[b] = false; - } - } - } - } - c = (CExpr*)(c->kids[2]); - } - - //record if this declares a judgement - if( ((CExpr*)defs[a])->getop()==PI && c->getop()==TYPE ){ - //std::cout << "This is a judgement" << std::endl; - judgements.push_back( syms[a] ); - //record if this declares a proof rule - }else if( c->getclass()==CEXPR && std::find( judgements.begin(), judgements.end(), c->kids[0] )!=judgements.end() ){ - std::cout << "Handle rule: " << ((SymSExpr*)syms[a])->s.c_str() << std::endl; - //std::cout << "These are required to input:" << std::endl; - //for( int b=0; b<(int)args.size(); b++ ){ - // if( argsNeed[b] ){ - // std::cout << ((SymSExpr*)args[b])->s.c_str() << std::endl; - // } - //} - os_enum << " rule_" << ((SymSExpr*)syms[a])->s.c_str() << "," << std::endl; - - os_print << " case rule_" << ((SymSExpr*)syms[a])->s.c_str() << ": os << \""; - os_print << ((SymSExpr*)syms[a])->s.c_str() << "\";break;" << std::endl; - - std::ostringstream os_args; - os_args << "("; - bool firstTime = true; - for( int b=0; b<(int)args.size(); b++ ){ - if( argsNeed[b] ){ - if( !firstTime ) - os_args << ","; - std::string str; - get_var_name( ((SymSExpr*)args[b])->s, str ); - os_args << " LFSCProof* " << str.c_str(); - firstTime = false; - } - } - if( !firstTime ){ - os_args << " "; - } - os_args << ")"; - - os_constructor_h << " static LFSCProof* make_" << ((SymSExpr*)syms[a])->s.c_str(); - os_constructor_h << os_args.str().c_str() << ";" << std::endl; - - os_constructor_c << "LFSCProof* LFSCProof::make_" << ((SymSExpr*)syms[a])->s.c_str(); - os_constructor_c << os_args.str().c_str() << "{" << std::endl; - os_constructor_c << " LFSCProof **kids = new LFSCProof *[" << (int)args.size()+1 << "];" << std::endl; - for( int b=0; b<(int)args.size(); b++ ){ - os_constructor_c << " kids[" << b << "] = "; - if( argsNeed[b] ){ - std::string str; - get_var_name( ((SymSExpr*)args[b])->s, str ); - os_constructor_c << str.c_str(); - }else{ - os_constructor_c << "hole"; - } - os_constructor_c << ";" << std::endl; - } - os_constructor_c << " kids[" << (int)args.size() << "] = 0;" << std::endl; - os_constructor_c << " return new LFSCProofC( rule_" << ((SymSExpr*)syms[a])->s.c_str() << ", kids );" << std::endl; - os_constructor_c << "}" << std::endl << std::endl; - } - } - - //write the header - static std::string filename( "lfsc_proof" ); - std::fstream fsh; - std::string fnameh( filename ); - fnameh.append(".h"); - fsh.open( fnameh.c_str(), std::ios::out ); - - fsh << "#ifndef LFSC_PROOF_LIB_H" << std::endl; - fsh << "#define LFSC_PROOF_LIB_H" << std::endl; - fsh << std::endl; - fsh << "#include " << std::endl; - fsh << std::endl; - fsh << "class LFSCProof{" << std::endl; - fsh << "protected:" << std::endl; - fsh << " enum{" << std::endl; - fsh << os_enum.str().c_str(); - fsh << " };" << std::endl; - fsh << " static LFSCProof* hole;" << std::endl; - fsh << " LFSCProof(){}" << std::endl; - fsh << "public:" << std::endl; - fsh << " virtual ~LFSCProof(){}" << std::endl; - fsh << " static void init();" << std::endl; - fsh << std::endl; - fsh << " //functions to build LFSC proofs" << std::endl; - fsh << os_constructor_h.str().c_str(); - fsh << std::endl; - fsh << " virtual void set_child( int i, LFSCProof* e ) {}" << std::endl; - fsh << " virtual void print( std::ostream& os ){}" << std::endl; - fsh << "};" << std::endl; - fsh << std::endl; - fsh << "class LFSCProofC : public LFSCProof{" << std::endl; - fsh << " short id;" << std::endl; - fsh << " LFSCProof **kids;" << std::endl; - fsh << "public:" << std::endl; - fsh << " LFSCProofC( short d_id, LFSCProof **d_kids ) : id( d_id ), kids( d_kids ){}" << std::endl; - fsh << " void set_child( int i, LFSCProof* e ) { kids[i] = e; }" << std::endl; - fsh << " void print( std::ostream& os );" << std::endl; - fsh << "};" << std::endl; - fsh << std::endl; - fsh << "class LFSCProofSym : public LFSCProof{" << std::endl; - fsh << "private:" << std::endl; - fsh << " std::string s;" << std::endl; - fsh << " LFSCProofSym( std::string ss ) : s( ss ){}" << std::endl; - fsh << "public:" << std::endl; - fsh << " static LFSCProofSym* make( std::string ss ) { return new LFSCProofSym( ss ); }" << std::endl; - fsh << " static LFSCProofSym* make( const char* ss ) { return new LFSCProofSym( std::string( ss ) ); }" << std::endl; - fsh << " ~LFSCProofSym(){}" << std::endl; - fsh << " void print( std::ostream& os ) { os << s.c_str(); }" << std::endl; - fsh << "};" << std::endl; - fsh << std::endl; - fsh << "class LFSCProofLam : public LFSCProof{" << std::endl; - fsh << " LFSCProofSym* var;" << std::endl; - fsh << " LFSCProof* body;" << std::endl; - fsh << " LFSCProof* typ;" << std::endl; - fsh << " LFSCProofLam( LFSCProofSym* d_var, LFSCProof* d_body, LFSCProof* d_typ ) : var( d_var ), body( d_body ), typ( d_typ ){}" << std::endl; - fsh << "public:" << std::endl; - fsh << " static LFSCProof* make( LFSCProofSym* d_var, LFSCProof* d_body, LFSCProof* d_typ = NULL ) {" << std::endl; - fsh << " return new LFSCProofLam( d_var, d_body, d_typ );" << std::endl; - fsh << " }" << std::endl; - fsh << " ~LFSCProofLam(){}" << std::endl; - fsh << std::endl; - fsh << " void print( std::ostream& os );" << std::endl; - fsh << "};" << std::endl; - fsh << std::endl; - fsh << "#endif" << std::endl; - - //write the cpp - std::fstream fsc; - std::string fnamec( filename ); - fnamec.append(".cpp"); - fsc.open( fnamec.c_str(), std::ios::out ); - - fsc << "#include \"lfsc_proof.h\"" << std::endl; - fsc << std::endl; - fsc << "LFSCProof* LFSCProof::hole = NULL;" << std::endl; - fsc << std::endl; - fsc << "void LFSCProof::init(){" << std::endl; - fsc << " hole = LFSCProofSym::make( \"_\" );" << std::endl; - fsc << "}" << std::endl; - fsc << std::endl; - fsc << "void LFSCProofC::print( std::ostream& os ){" << std::endl; - fsc << " os << \"(\";" << std::endl; - fsc << " switch( id ){" << std::endl; - fsc << os_print.str().c_str(); - fsc << " }" << std::endl; - fsc << " int counter = 0;" << std::endl; - fsc << " while( kids[counter] ){" << std::endl; - fsc << " os << \" \";" << std::endl; - fsc << " kids[counter]->print( os );" << std::endl; - fsc << " counter++;" << std::endl; - fsc << " }" << std::endl; - fsc << " os << \")\";" << std::endl; - fsc << "}" << std::endl; - fsc << std::endl; - fsc << "void LFSCProofLam::print( std::ostream& os ){" << std::endl; - fsc << " os << \"(\";" << std::endl; - fsc << " if( typ ){" << std::endl; - fsc << " os << \"% \";" << std::endl; - fsc << " }else{" << std::endl; - fsc << " os << \"\\\\ \";" << std::endl; - fsc << " }" << std::endl; - fsc << " var->print( os );" << std::endl; - fsc << " if( typ ){" << std::endl; - fsc << " os << \" \";" << std::endl; - fsc << " typ->print( os );" << std::endl; - fsc << " }" << std::endl; - fsc << " os << std::endl;" << std::endl; - fsc << " body->print( os );" << std::endl; - fsc << " os << \")\";" << std::endl; - fsc << "}" << std::endl; - fsc << std::endl; - fsc << os_constructor_c.str().c_str(); - fsc << std::endl; - } -} +#include "libwriter.h" +#include +#include +#include + +void libwriter::get_var_name( const std::string& n, std::string& nn ) { + nn = std::string( n.c_str() ); + for( int i = 0; i <(int)n.length(); i++ ){ + char c = n[i]; + if (c <= 47) + c += 65; + else if (c >= 58 && c <= 64) + c += 97-58; + if ((c >= 91 && c <= 94) || c == 96) + c += 104-91; + else if (c >= 123) + c -= 4; + nn[i] = c; + } +} + +void libwriter::write_file() +{ + //std::cout << "write lib" << std::endl; + std::ostringstream os_enum; + std::ostringstream os_print; + std::ostringstream os_constructor_h; + std::ostringstream os_constructor_c; + + for ( int a=0; a<(int)syms.size(); a++ ) { + //std::cout << "sym #" << (a+1) << ": "; + //std::cout << ((SymSExpr*)syms[a])->s.c_str() << std::endl; + //defs[a]->print( std::cout ); + //std::cout << std::endl; + + if( defs[a]->getclass()==CEXPR ){ + //calculate which arguments are required for input + std::vector< Expr* > args; + std::vector< bool > argsNeed; + std::vector< Expr* > argTypes; + CExpr* c = ((CExpr*)defs[a]); + while( c->getop()==PI ){ + //std::cout << c->kids[0] << std::endl; + if( ((CExpr*)c->kids[1])->getop()!=RUN ){ + args.push_back( c->kids[0] ); + argsNeed.push_back( true ); + argTypes.push_back( c->kids[1] ); + } + for( int b=0; b<(int)args.size(); b++ ){ + if( argsNeed[b] ){ + if( ((CExpr*)c->kids[1])->getop()==RUN ){ + if( ((CExpr*)c->kids[1])->kids[1]->free_in( args[b] ) ){ + argsNeed[b] = false; + } + }else{ + if( c->kids[1]->free_in( args[b] ) ){ + argsNeed[b] = false; + } + } + } + } + c = (CExpr*)(c->kids[2]); + } + + //record if this declares a judgement + if( ((CExpr*)defs[a])->getop()==PI && c->getop()==TYPE ){ + //std::cout << "This is a judgement" << std::endl; + judgements.push_back( syms[a] ); + //record if this declares a proof rule + }else if( c->getclass()==CEXPR && std::find( judgements.begin(), judgements.end(), c->kids[0] )!=judgements.end() ){ + std::cout << "Handle rule: " << ((SymSExpr*)syms[a])->s.c_str() << std::endl; + //std::cout << "These are required to input:" << std::endl; + //for( int b=0; b<(int)args.size(); b++ ){ + // if( argsNeed[b] ){ + // std::cout << ((SymSExpr*)args[b])->s.c_str() << std::endl; + // } + //} + os_enum << " rule_" << ((SymSExpr*)syms[a])->s.c_str() << "," << std::endl; + + os_print << " case rule_" << ((SymSExpr*)syms[a])->s.c_str() << ": os << \""; + os_print << ((SymSExpr*)syms[a])->s.c_str() << "\";break;" << std::endl; + + std::ostringstream os_args; + os_args << "("; + bool firstTime = true; + for( int b=0; b<(int)args.size(); b++ ){ + if( argsNeed[b] ){ + if( !firstTime ) + os_args << ","; + std::string str; + get_var_name( ((SymSExpr*)args[b])->s, str ); + os_args << " LFSCProof* " << str.c_str(); + firstTime = false; + } + } + if( !firstTime ){ + os_args << " "; + } + os_args << ")"; + + os_constructor_h << " static LFSCProof* make_" << ((SymSExpr*)syms[a])->s.c_str(); + os_constructor_h << os_args.str().c_str() << ";" << std::endl; + + os_constructor_c << "LFSCProof* LFSCProof::make_" << ((SymSExpr*)syms[a])->s.c_str(); + os_constructor_c << os_args.str().c_str() << "{" << std::endl; + os_constructor_c << " LFSCProof **kids = new LFSCProof *[" << (int)args.size()+1 << "];" << std::endl; + for( int b=0; b<(int)args.size(); b++ ){ + os_constructor_c << " kids[" << b << "] = "; + if( argsNeed[b] ){ + std::string str; + get_var_name( ((SymSExpr*)args[b])->s, str ); + os_constructor_c << str.c_str(); + }else{ + os_constructor_c << "hole"; + } + os_constructor_c << ";" << std::endl; + } + os_constructor_c << " kids[" << (int)args.size() << "] = 0;" << std::endl; + os_constructor_c << " return new LFSCProofC( rule_" << ((SymSExpr*)syms[a])->s.c_str() << ", kids );" << std::endl; + os_constructor_c << "}" << std::endl << std::endl; + } + } + + //write the header + static std::string filename( "lfsc_proof" ); + std::fstream fsh; + std::string fnameh( filename ); + fnameh.append(".h"); + fsh.open( fnameh.c_str(), std::ios::out ); + + fsh << "#ifndef LFSC_PROOF_LIB_H" << std::endl; + fsh << "#define LFSC_PROOF_LIB_H" << std::endl; + fsh << std::endl; + fsh << "#include " << std::endl; + fsh << std::endl; + fsh << "class LFSCProof{" << std::endl; + fsh << "protected:" << std::endl; + fsh << " enum{" << std::endl; + fsh << os_enum.str().c_str(); + fsh << " };" << std::endl; + fsh << " static LFSCProof* hole;" << std::endl; + fsh << " LFSCProof(){}" << std::endl; + fsh << "public:" << std::endl; + fsh << " virtual ~LFSCProof(){}" << std::endl; + fsh << " static void init();" << std::endl; + fsh << std::endl; + fsh << " //functions to build LFSC proofs" << std::endl; + fsh << os_constructor_h.str().c_str(); + fsh << std::endl; + fsh << " virtual void set_child( int i, LFSCProof* e ) {}" << std::endl; + fsh << " virtual void print( std::ostream& os ){}" << std::endl; + fsh << "};" << std::endl; + fsh << std::endl; + fsh << "class LFSCProofC : public LFSCProof{" << std::endl; + fsh << " short id;" << std::endl; + fsh << " LFSCProof **kids;" << std::endl; + fsh << "public:" << std::endl; + fsh << " LFSCProofC( short d_id, LFSCProof **d_kids ) : id( d_id ), kids( d_kids ){}" << std::endl; + fsh << " void set_child( int i, LFSCProof* e ) { kids[i] = e; }" << std::endl; + fsh << " void print( std::ostream& os );" << std::endl; + fsh << "};" << std::endl; + fsh << std::endl; + fsh << "class LFSCProofSym : public LFSCProof{" << std::endl; + fsh << "private:" << std::endl; + fsh << " std::string s;" << std::endl; + fsh << " LFSCProofSym( std::string ss ) : s( ss ){}" << std::endl; + fsh << "public:" << std::endl; + fsh << " static LFSCProofSym* make( std::string ss ) { return new LFSCProofSym( ss ); }" << std::endl; + fsh << " static LFSCProofSym* make( const char* ss ) { return new LFSCProofSym( std::string( ss ) ); }" << std::endl; + fsh << " ~LFSCProofSym(){}" << std::endl; + fsh << " void print( std::ostream& os ) { os << s.c_str(); }" << std::endl; + fsh << "};" << std::endl; + fsh << std::endl; + fsh << "class LFSCProofLam : public LFSCProof{" << std::endl; + fsh << " LFSCProofSym* var;" << std::endl; + fsh << " LFSCProof* body;" << std::endl; + fsh << " LFSCProof* typ;" << std::endl; + fsh << " LFSCProofLam( LFSCProofSym* d_var, LFSCProof* d_body, LFSCProof* d_typ ) : var( d_var ), body( d_body ), typ( d_typ ){}" << std::endl; + fsh << "public:" << std::endl; + fsh << " static LFSCProof* make( LFSCProofSym* d_var, LFSCProof* d_body, LFSCProof* d_typ = NULL ) {" << std::endl; + fsh << " return new LFSCProofLam( d_var, d_body, d_typ );" << std::endl; + fsh << " }" << std::endl; + fsh << " ~LFSCProofLam(){}" << std::endl; + fsh << std::endl; + fsh << " void print( std::ostream& os );" << std::endl; + fsh << "};" << std::endl; + fsh << std::endl; + fsh << "#endif" << std::endl; + + //write the cpp + std::fstream fsc; + std::string fnamec( filename ); + fnamec.append(".cpp"); + fsc.open( fnamec.c_str(), std::ios::out ); + + fsc << "#include \"lfsc_proof.h\"" << std::endl; + fsc << std::endl; + fsc << "LFSCProof* LFSCProof::hole = NULL;" << std::endl; + fsc << std::endl; + fsc << "void LFSCProof::init(){" << std::endl; + fsc << " hole = LFSCProofSym::make( \"_\" );" << std::endl; + fsc << "}" << std::endl; + fsc << std::endl; + fsc << "void LFSCProofC::print( std::ostream& os ){" << std::endl; + fsc << " os << \"(\";" << std::endl; + fsc << " switch( id ){" << std::endl; + fsc << os_print.str().c_str(); + fsc << " }" << std::endl; + fsc << " int counter = 0;" << std::endl; + fsc << " while( kids[counter] ){" << std::endl; + fsc << " os << \" \";" << std::endl; + fsc << " kids[counter]->print( os );" << std::endl; + fsc << " counter++;" << std::endl; + fsc << " }" << std::endl; + fsc << " os << \")\";" << std::endl; + fsc << "}" << std::endl; + fsc << std::endl; + fsc << "void LFSCProofLam::print( std::ostream& os ){" << std::endl; + fsc << " os << \"(\";" << std::endl; + fsc << " if( typ ){" << std::endl; + fsc << " os << \"% \";" << std::endl; + fsc << " }else{" << std::endl; + fsc << " os << \"\\\\ \";" << std::endl; + fsc << " }" << std::endl; + fsc << " var->print( os );" << std::endl; + fsc << " if( typ ){" << std::endl; + fsc << " os << \" \";" << std::endl; + fsc << " typ->print( os );" << std::endl; + fsc << " }" << std::endl; + fsc << " os << std::endl;" << std::endl; + fsc << " body->print( os );" << std::endl; + fsc << " os << \")\";" << std::endl; + fsc << "}" << std::endl; + fsc << std::endl; + fsc << os_constructor_c.str().c_str(); + fsc << std::endl; + } +} diff --git a/proofs/lfsc_checker/libwriter.h b/proofs/lfsc_checker/libwriter.h index 093cf541b..91db5e911 100644 --- a/proofs/lfsc_checker/libwriter.h +++ b/proofs/lfsc_checker/libwriter.h @@ -1,28 +1,28 @@ -#ifndef LIB_WRITER_H -#define LIB_WRITER_H - -#include "expr.h" -#include - -class libwriter -{ -private: - std::vector< Expr* > syms; - std::vector< Expr* > defs; - - std::vector< Expr* > judgements; - //get the variable name - void get_var_name( const std::string& n, std::string& nn ); -public: - libwriter(){} - virtual ~libwriter(){} - - void add_symbol( Expr* s, Expr* t ) { - syms.push_back( s ); - defs.push_back( t ); - } - - void write_file(); -}; - -#endif +#ifndef LIB_WRITER_H +#define LIB_WRITER_H + +#include "expr.h" +#include + +class libwriter +{ +private: + std::vector< Expr* > syms; + std::vector< Expr* > defs; + + std::vector< Expr* > judgements; + //get the variable name + void get_var_name( const std::string& n, std::string& nn ); +public: + libwriter(){} + virtual ~libwriter(){} + + void add_symbol( Expr* s, Expr* t ) { + syms.push_back( s ); + defs.push_back( t ); + } + + void write_file(); +}; + +#endif diff --git a/proofs/lfsc_checker/print_smt2.cpp b/proofs/lfsc_checker/print_smt2.cpp index 34cb00cc4..40d9d1206 100644 --- a/proofs/lfsc_checker/print_smt2.cpp +++ b/proofs/lfsc_checker/print_smt2.cpp @@ -1,122 +1,122 @@ -#include "print_smt2.h" - -#ifdef PRINT_SMT2 - -void print_smt2( Expr* p, std::ostream& s, short mode ) -{ - switch( p->getclass() ) - { - case CEXPR: - { - switch( p->getop() ) - { - case APP: - { +#include "print_smt2.h" + +#ifdef PRINT_SMT2 + +void print_smt2( Expr* p, std::ostream& s, short mode ) +{ + switch( p->getclass() ) + { + case CEXPR: + { + switch( p->getop() ) + { + case APP: + { std::vector args; - Expr *head = p->collect_args(args, false); - short newMode = get_mode( head ); - if( is_smt2_poly_formula( head ) ) - { - s << "("; - head->print( s ); - s << " "; - print_smt2( args[1], s, newMode ); - s << " "; - print_smt2( args[2], s, newMode ); - s << ")"; - } - else if( ( mode==2 || mode==3 ) && mode==newMode ) - { - print_smt2( args[0], s, newMode ); - s << " "; - print_smt2( args[1], s, newMode ); - } - else if( newMode==1 ) - { - if( mode!=1 || newMode!=mode ){ - s << "("; - } - print_smt2( args[2], s, newMode ); - s << " "; - print_smt2( args[3], s, 0 ); - if( mode!=1 || newMode!=mode ){ - s << ")"; - } - } - else - { - s << "("; - switch( newMode ) - { - case 4: s << "=>";break; - default: head->print( s );break; - } - s << " "; - for( int a=0; a<(int)args.size(); a++ ){ - print_smt2( args[a], s, newMode ); - if( a!=(int)args.size()-1 ) - s << " "; - } - s << ")"; - } - } - break; - default: - std::cout << "Unhandled op " << p->getop() << std::endl; - break; - } - } - break; - case HOLE_EXPR: - { - HoleExpr *e = (HoleExpr *)p; - if( e->val ){ - print_smt2( e->val, s, mode ); - }else{ - s << "_"; - } - } - break; - case SYMS_EXPR: - case SYM_EXPR: - if( ((SymExpr*)p)->val ) - print_smt2( ((SymExpr*)p)->val, s, mode ); - else - p->print( s ); - break; - default: - std::cout << "Unhandled class " << p->getclass() << std::endl; - break; - } -} - -bool is_smt2_poly_formula( Expr* e ) -{ - if( e->getclass()==SYMS_EXPR ) - { - SymSExpr* s = (SymSExpr*)e; - static std::string eq("="); - static std::string distinct("distinct"); - return s->s==eq || s->s==distinct; - }else{ - return false; - } -} - -short get_mode( Expr* e ) -{ - if( e->getclass()==SYMS_EXPR ){ - SymSExpr* s = (SymSExpr*)e; - static std::string applys("apply"); - if ( s->s==applys ) return 1; - static std::string ands("and"); - if ( s->s==ands ) return 2; - static std::string ors("or"); - if ( s->s==ors ) return 3; - static std::string impls("impl"); - if ( s->s==impls ) return 4; - } - return 0; -} - -#endif + Expr *head = p->collect_args(args, false); + short newMode = get_mode( head ); + if( is_smt2_poly_formula( head ) ) + { + s << "("; + head->print( s ); + s << " "; + print_smt2( args[1], s, newMode ); + s << " "; + print_smt2( args[2], s, newMode ); + s << ")"; + } + else if( ( mode==2 || mode==3 ) && mode==newMode ) + { + print_smt2( args[0], s, newMode ); + s << " "; + print_smt2( args[1], s, newMode ); + } + else if( newMode==1 ) + { + if( mode!=1 || newMode!=mode ){ + s << "("; + } + print_smt2( args[2], s, newMode ); + s << " "; + print_smt2( args[3], s, 0 ); + if( mode!=1 || newMode!=mode ){ + s << ")"; + } + } + else + { + s << "("; + switch( newMode ) + { + case 4: s << "=>";break; + default: head->print( s );break; + } + s << " "; + for( int a=0; a<(int)args.size(); a++ ){ + print_smt2( args[a], s, newMode ); + if( a!=(int)args.size()-1 ) + s << " "; + } + s << ")"; + } + } + break; + default: + std::cout << "Unhandled op " << p->getop() << std::endl; + break; + } + } + break; + case HOLE_EXPR: + { + HoleExpr *e = (HoleExpr *)p; + if( e->val ){ + print_smt2( e->val, s, mode ); + }else{ + s << "_"; + } + } + break; + case SYMS_EXPR: + case SYM_EXPR: + if( ((SymExpr*)p)->val ) + print_smt2( ((SymExpr*)p)->val, s, mode ); + else + p->print( s ); + break; + default: + std::cout << "Unhandled class " << p->getclass() << std::endl; + break; + } +} + +bool is_smt2_poly_formula( Expr* e ) +{ + if( e->getclass()==SYMS_EXPR ) + { + SymSExpr* s = (SymSExpr*)e; + static std::string eq("="); + static std::string distinct("distinct"); + return s->s==eq || s->s==distinct; + }else{ + return false; + } +} + +short get_mode( Expr* e ) +{ + if( e->getclass()==SYMS_EXPR ){ + SymSExpr* s = (SymSExpr*)e; + static std::string applys("apply"); + if ( s->s==applys ) return 1; + static std::string ands("and"); + if ( s->s==ands ) return 2; + static std::string ors("or"); + if ( s->s==ors ) return 3; + static std::string impls("impl"); + if ( s->s==impls ) return 4; + } + return 0; +} + +#endif diff --git a/proofs/lfsc_checker/print_smt2.h b/proofs/lfsc_checker/print_smt2.h index c70b1dfa4..9bee0e81c 100644 --- a/proofs/lfsc_checker/print_smt2.h +++ b/proofs/lfsc_checker/print_smt2.h @@ -1,17 +1,17 @@ -#ifndef PRINT_SMT2_H -#define PRINT_SMT2_H - -#define PRINT_SMT2 - -#include "expr.h" - -#ifdef PRINT_SMT2 -void print_smt2( Expr* p, std::ostream& s, short mode = 0 ); - -bool is_smt2_poly_formula( Expr* p ); -short get_mode( Expr* p ); - -#endif - - -#endif +#ifndef PRINT_SMT2_H +#define PRINT_SMT2_H + +#define PRINT_SMT2 + +#include "expr.h" + +#ifdef PRINT_SMT2 +void print_smt2( Expr* p, std::ostream& s, short mode = 0 ); + +bool is_smt2_poly_formula( Expr* p ); +short get_mode( Expr* p ); + +#endif + + +#endif diff --git a/proofs/lfsc_checker/sccwriter.cpp b/proofs/lfsc_checker/sccwriter.cpp index d11a96b19..5c1da2a3f 100644 --- a/proofs/lfsc_checker/sccwriter.cpp +++ b/proofs/lfsc_checker/sccwriter.cpp @@ -1,335 +1,335 @@ -#include "sccwriter.h" - -#include -#include - -int sccwriter::exprCount = 0; -int sccwriter::strCount = 0; -int sccwriter::argsCount = 0; -int sccwriter::rnumCount = 0; - -int sccwriter::get_prog_index( const std::string& str ) -{ - for( int a=0; a<(int)progNames.size(); a++ ){ - if( progNames[a]==str ){ - return a; - } - } - return -1; -} - -int sccwriter::get_prog_index_by_expr( Expr* e ) -{ - for( int a=0; a<(int)progPtrs.size(); a++ ){ - if( progPtrs[a]==e ){ - return a; - } - } - return -1; -} - -bool sccwriter::is_var( const std::string& str ) -{ - for( int a=0; a<(int)vars.size(); a++ ){ - if( vars[a]==str ){ - return true; - } - } - return false; -} - -void sccwriter::add_global_sym( const std::string& str ) -{ - for( int a=0; a<(int)globalSyms.size(); a++ ){ - if( globalSyms[a]==str ){ - return; - } - } - globalSyms.push_back( str ); -} - -void sccwriter::indent( std::ostream& os, int ind ) -{ - for( int a=0; akids[1]; - int counter = 0; - //write each argument - while( progvars->kids[counter] ) - { - if( counter!=0 ) - { - os << ", "; - } - os << "Expr* "; - write_variable( ((SymSExpr*)progvars->kids[counter])->s, os ); - //add to vars if options are set to do so - if( opts&opt_write_add_args ) - { - vars.push_back( ((SymSExpr*)progvars->kids[counter])->s ); - } - counter++; - } - os << " )"; - if( opts&opt_write_call_debug ) - { - os << "{" << std::endl; - indent( os, 1 ); - os << "std::cout << \"Call function " << fname.c_str() << " with arguments \";" << std::endl; - counter = 0; - while( progvars->kids[counter] ) - { - if( counter!=0 ) - { - indent( os, 1 ); - os << "std::cout << \", \";" << std::endl; - } - indent( os, 1 ); - write_variable( ((SymSExpr*)progvars->kids[counter])->s, os ); - os << "->print( std::cout );" << std::endl; - counter++; - } - indent( os, 1 ); - os << "std::cout << std::endl;" << std::endl; - } -} - -void sccwriter::get_function_name( const std::string& pname, std::string& fname ) -{ - fname = std::string( "f_" ); - fname.append( pname ); -} - -void sccwriter::write_variable( const std::string& n, std::ostream& os ) -{ - std::string nn; - get_var_name( n, nn ); - os << nn.c_str(); -} - -void sccwriter::get_var_name( const std::string& n, std::string& nn ) { - nn = std::string( n.c_str() ); - for( int i = 0; i <(int)n.length(); i++ ){ - char c = n[i]; - if (c <= 47) - c += 65; - else if (c >= 58 && c <= 64) - c += 97-58; - if ((c >= 91 && c <= 94) || c == 96) - c += 104-91; - else if (c >= 123) - c -= 4; - nn[i] = c; - } -} - -void sccwriter::write_file() -{ - static std::string filename( "scccode" ); - - //writer the h file - std::fstream fsh; - std::string fnameh( filename ); - fnameh.append(".h"); - fsh.open( fnameh.c_str(), std::ios::out ); - //write the header in h - fsh << "#ifndef SCC_CODE_H" << std::endl; - fsh << "#define SCC_CODE_H" << std::endl << std::endl; - //include necessary files in h file - fsh << "#include \"check.h\"" << std::endl << std::endl; - //write the init function - fsh << "void init_compiled_scc();" << std::endl << std::endl; - //write the entry function - fsh << "Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args );" << std::endl << std::endl; - //write the side condition code functions - for( int n=0; n<(int)progs.size(); n++ ) - { - //write the header in the h file - fsh << "inline "; - write_function_header( fsh, n ); - fsh << ";" << std::endl << std::endl; - } - fsh << "#endif" << std::endl << std::endl; - fsh.close(); - - - //writer the cpp code - std::fstream fsc; - std::string fnamec( filename ); - fnamec.append(".cpp"); - fsc.open( fnamec.c_str(), std::ios::out ); - //include the h file in the cpp - fsc << "#include \"scccode.h\"" << std::endl << std::endl; - std::ostringstream fsc_funcs; - //write the side condition code functions - for( currProgram=0; currProgram<(int)progs.size(); currProgram++ ) - { - //reset naming counters - vars.clear(); - exprCount = 0; - strCount = 0; - argsCount = 0; - rnumCount = 0; - - //for debugging - std::cout << "program #" << currProgram << " " << progNames[currProgram].c_str() << std::endl; - - //write the function header - write_function_header( fsc_funcs, currProgram, opt_write_add_args|options ); - if( (options&opt_write_call_debug)==0 ) - { - fsc_funcs << "{" << std::endl; - } - //write the code - //std::vector< std::string > cleanVec; - //write_code( get_prog( n )->kids[2], fsc, 1, "return ", cleanVec ); - //debug_write_code( progs[n].second->kids[2], fsc, 1 ); - std::string expr; - write_expr( get_prog( currProgram )->kids[2], fsc_funcs, 1, expr ); - indent( fsc_funcs, 1 ); - fsc_funcs << "return " << expr.c_str() << ";" << std::endl; - fsc_funcs << "}" << std::endl << std::endl; - } - //write the predefined symbols necessary - symbols and progs - for( int a=0; a<(int)globalSyms.size(); a++ ) - { - fsc << "Expr* e_" << globalSyms[a].c_str() << ";" << std::endl; - } - for( int a=0; a<(int)progs.size(); a++ ) - { - fsc << "Expr* e_" << progNames[a].c_str() << ";" << std::endl; - } - fsc << std::endl; - //write the init function - initialize symbols and progs - fsc << "void init_compiled_scc(){" << std::endl; - for( int a=0; a<(int)globalSyms.size(); a++ ) - { - indent( fsc, 1 ); - fsc << "e_" << globalSyms[a].c_str() << " = symbols->get(\"" << globalSyms[a].c_str() << "\").first;" << std::endl; - } - for( int a=0; a<(int)progs.size(); a++ ) - { - indent( fsc, 1 ); - fsc << "e_" << progNames[a].c_str() << " = progs[\"" << progNames[a].c_str() << "\"];" << std::endl; - } - fsc << "}" << std::endl << std::endl; - fsc << "Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args ){" << std::endl; - //for( int n=0; n<(int)progs.size(); n++ ){ - // indent( fsc, 1 ); - // fsc << "static std::string s_" << progNames[n].c_str() << " = std::string( \"" << progNames[n].c_str() << "\" );" << std::endl; - //} - for( int n=0; n<(int)progs.size(); n++ ){ - indent( fsc, 1 ); - if( n!=0 ){ - fsc << "}else "; - } - //for each function, test to see if the string matches the name of the function - fsc << "if( p==e_" << progNames[n].c_str() << " ){" << std::endl; - indent( fsc, 2 ); - std::string fname; - get_function_name( progNames[n], fname ); - //map the function to the proper function - fsc << "return " << fname.c_str() << "( "; - //write the arguments to the function from args - CExpr* progvars = (CExpr*)get_prog( n )->kids[1]; - int counter = 0; - bool firstTime = true; - while( progvars->kids[counter] ) - { - if( !firstTime ) - { - fsc << ", "; - } - fsc << "args[" << counter << "]"; - firstTime = false; - counter++; - } - fsc << " );" << std::endl; - } - indent( fsc, 1 ); - fsc << "}else{" << std::endl; - indent( fsc, 2 ); - //return null in the case the function could not be found - fsc << "return NULL;" << std::endl; - indent( fsc, 1 ); - fsc << "}" << std::endl; - fsc << "}" << std::endl << std::endl; - fsc << fsc_funcs.str().c_str(); - - fsc.close(); -} - -void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* retModStr, int opts ) -{ - std::string retModString; - std::string incString; - if ( retModStr ) - { - retModString = std::string( retModStr ); - retModString.append( " = " ); - incString = std::string( retModStr ); - incString.append( "->inc();" ); - } - switch( code->getclass() ) - { - case INT_EXPR: - { - indent( os, ind ); - os << retModString.c_str(); - os << "new IntExpr( " << mpz_get_si( ((IntExpr*)code)->n ) << " );" << std::endl; - indent( os, ind ); - os << incString.c_str() << std::endl; - } - break; - case RAT_EXPR: - { - mpz_t num, den; - mpz_init(num); - mpz_init(den); - mpq_get_num( num, ((RatExpr*)code)->n ); - mpq_get_den( den, ((RatExpr*)code)->n ); - indent( os, ind ); - os << retModString.c_str(); - os << "new RatExpr( " << mpz_get_si( num ) << ", " << mpz_get_si( den ) << " );" << std::endl; - indent( os, ind ); - os << incString.c_str() << std::endl; - } - break; - case SYMS_EXPR: - { - //if it is a variable, simply write it to buffer - if( is_var( ((SymSExpr*)code)->s ) ) - { - indent( os, ind ); - os << retModString.c_str(); - write_variable( ((SymSExpr*)code)->s.c_str(), os ); - os << ";" << std::endl; - } - else //else must look at symbol lookup table - { - std::string var; - get_var_name( ((SymSExpr*)code)->s, var ); - indent( os, ind ); - os << retModString.c_str() << "e_" << var.c_str() << ";" << std::endl; - add_global_sym( var ); - } - indent( os, ind ); - os << incString.c_str() << std::endl; - } - break; - default: - switch( code->getop() ) - { +#include "sccwriter.h" + +#include +#include + +int sccwriter::exprCount = 0; +int sccwriter::strCount = 0; +int sccwriter::argsCount = 0; +int sccwriter::rnumCount = 0; + +int sccwriter::get_prog_index( const std::string& str ) +{ + for( int a=0; a<(int)progNames.size(); a++ ){ + if( progNames[a]==str ){ + return a; + } + } + return -1; +} + +int sccwriter::get_prog_index_by_expr( Expr* e ) +{ + for( int a=0; a<(int)progPtrs.size(); a++ ){ + if( progPtrs[a]==e ){ + return a; + } + } + return -1; +} + +bool sccwriter::is_var( const std::string& str ) +{ + for( int a=0; a<(int)vars.size(); a++ ){ + if( vars[a]==str ){ + return true; + } + } + return false; +} + +void sccwriter::add_global_sym( const std::string& str ) +{ + for( int a=0; a<(int)globalSyms.size(); a++ ){ + if( globalSyms[a]==str ){ + return; + } + } + globalSyms.push_back( str ); +} + +void sccwriter::indent( std::ostream& os, int ind ) +{ + for( int a=0; akids[1]; + int counter = 0; + //write each argument + while( progvars->kids[counter] ) + { + if( counter!=0 ) + { + os << ", "; + } + os << "Expr* "; + write_variable( ((SymSExpr*)progvars->kids[counter])->s, os ); + //add to vars if options are set to do so + if( opts&opt_write_add_args ) + { + vars.push_back( ((SymSExpr*)progvars->kids[counter])->s ); + } + counter++; + } + os << " )"; + if( opts&opt_write_call_debug ) + { + os << "{" << std::endl; + indent( os, 1 ); + os << "std::cout << \"Call function " << fname.c_str() << " with arguments \";" << std::endl; + counter = 0; + while( progvars->kids[counter] ) + { + if( counter!=0 ) + { + indent( os, 1 ); + os << "std::cout << \", \";" << std::endl; + } + indent( os, 1 ); + write_variable( ((SymSExpr*)progvars->kids[counter])->s, os ); + os << "->print( std::cout );" << std::endl; + counter++; + } + indent( os, 1 ); + os << "std::cout << std::endl;" << std::endl; + } +} + +void sccwriter::get_function_name( const std::string& pname, std::string& fname ) +{ + fname = std::string( "f_" ); + fname.append( pname ); +} + +void sccwriter::write_variable( const std::string& n, std::ostream& os ) +{ + std::string nn; + get_var_name( n, nn ); + os << nn.c_str(); +} + +void sccwriter::get_var_name( const std::string& n, std::string& nn ) { + nn = std::string( n.c_str() ); + for( int i = 0; i <(int)n.length(); i++ ){ + char c = n[i]; + if (c <= 47) + c += 65; + else if (c >= 58 && c <= 64) + c += 97-58; + if ((c >= 91 && c <= 94) || c == 96) + c += 104-91; + else if (c >= 123) + c -= 4; + nn[i] = c; + } +} + +void sccwriter::write_file() +{ + static std::string filename( "scccode" ); + + //writer the h file + std::fstream fsh; + std::string fnameh( filename ); + fnameh.append(".h"); + fsh.open( fnameh.c_str(), std::ios::out ); + //write the header in h + fsh << "#ifndef SCC_CODE_H" << std::endl; + fsh << "#define SCC_CODE_H" << std::endl << std::endl; + //include necessary files in h file + fsh << "#include \"check.h\"" << std::endl << std::endl; + //write the init function + fsh << "void init_compiled_scc();" << std::endl << std::endl; + //write the entry function + fsh << "Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args );" << std::endl << std::endl; + //write the side condition code functions + for( int n=0; n<(int)progs.size(); n++ ) + { + //write the header in the h file + fsh << "inline "; + write_function_header( fsh, n ); + fsh << ";" << std::endl << std::endl; + } + fsh << "#endif" << std::endl << std::endl; + fsh.close(); + + + //writer the cpp code + std::fstream fsc; + std::string fnamec( filename ); + fnamec.append(".cpp"); + fsc.open( fnamec.c_str(), std::ios::out ); + //include the h file in the cpp + fsc << "#include \"scccode.h\"" << std::endl << std::endl; + std::ostringstream fsc_funcs; + //write the side condition code functions + for( currProgram=0; currProgram<(int)progs.size(); currProgram++ ) + { + //reset naming counters + vars.clear(); + exprCount = 0; + strCount = 0; + argsCount = 0; + rnumCount = 0; + + //for debugging + std::cout << "program #" << currProgram << " " << progNames[currProgram].c_str() << std::endl; + + //write the function header + write_function_header( fsc_funcs, currProgram, opt_write_add_args|options ); + if( (options&opt_write_call_debug)==0 ) + { + fsc_funcs << "{" << std::endl; + } + //write the code + //std::vector< std::string > cleanVec; + //write_code( get_prog( n )->kids[2], fsc, 1, "return ", cleanVec ); + //debug_write_code( progs[n].second->kids[2], fsc, 1 ); + std::string expr; + write_expr( get_prog( currProgram )->kids[2], fsc_funcs, 1, expr ); + indent( fsc_funcs, 1 ); + fsc_funcs << "return " << expr.c_str() << ";" << std::endl; + fsc_funcs << "}" << std::endl << std::endl; + } + //write the predefined symbols necessary - symbols and progs + for( int a=0; a<(int)globalSyms.size(); a++ ) + { + fsc << "Expr* e_" << globalSyms[a].c_str() << ";" << std::endl; + } + for( int a=0; a<(int)progs.size(); a++ ) + { + fsc << "Expr* e_" << progNames[a].c_str() << ";" << std::endl; + } + fsc << std::endl; + //write the init function - initialize symbols and progs + fsc << "void init_compiled_scc(){" << std::endl; + for( int a=0; a<(int)globalSyms.size(); a++ ) + { + indent( fsc, 1 ); + fsc << "e_" << globalSyms[a].c_str() << " = symbols->get(\"" << globalSyms[a].c_str() << "\").first;" << std::endl; + } + for( int a=0; a<(int)progs.size(); a++ ) + { + indent( fsc, 1 ); + fsc << "e_" << progNames[a].c_str() << " = progs[\"" << progNames[a].c_str() << "\"];" << std::endl; + } + fsc << "}" << std::endl << std::endl; + fsc << "Expr* run_compiled_scc( Expr* p, std::vector< Expr* >& args ){" << std::endl; + //for( int n=0; n<(int)progs.size(); n++ ){ + // indent( fsc, 1 ); + // fsc << "static std::string s_" << progNames[n].c_str() << " = std::string( \"" << progNames[n].c_str() << "\" );" << std::endl; + //} + for( int n=0; n<(int)progs.size(); n++ ){ + indent( fsc, 1 ); + if( n!=0 ){ + fsc << "}else "; + } + //for each function, test to see if the string matches the name of the function + fsc << "if( p==e_" << progNames[n].c_str() << " ){" << std::endl; + indent( fsc, 2 ); + std::string fname; + get_function_name( progNames[n], fname ); + //map the function to the proper function + fsc << "return " << fname.c_str() << "( "; + //write the arguments to the function from args + CExpr* progvars = (CExpr*)get_prog( n )->kids[1]; + int counter = 0; + bool firstTime = true; + while( progvars->kids[counter] ) + { + if( !firstTime ) + { + fsc << ", "; + } + fsc << "args[" << counter << "]"; + firstTime = false; + counter++; + } + fsc << " );" << std::endl; + } + indent( fsc, 1 ); + fsc << "}else{" << std::endl; + indent( fsc, 2 ); + //return null in the case the function could not be found + fsc << "return NULL;" << std::endl; + indent( fsc, 1 ); + fsc << "}" << std::endl; + fsc << "}" << std::endl << std::endl; + fsc << fsc_funcs.str().c_str(); + + fsc.close(); +} + +void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* retModStr, int opts ) +{ + std::string retModString; + std::string incString; + if ( retModStr ) + { + retModString = std::string( retModStr ); + retModString.append( " = " ); + incString = std::string( retModStr ); + incString.append( "->inc();" ); + } + switch( code->getclass() ) + { + case INT_EXPR: + { + indent( os, ind ); + os << retModString.c_str(); + os << "new IntExpr( " << mpz_get_si( ((IntExpr*)code)->n ) << " );" << std::endl; + indent( os, ind ); + os << incString.c_str() << std::endl; + } + break; + case RAT_EXPR: + { + mpz_t num, den; + mpz_init(num); + mpz_init(den); + mpq_get_num( num, ((RatExpr*)code)->n ); + mpq_get_den( den, ((RatExpr*)code)->n ); + indent( os, ind ); + os << retModString.c_str(); + os << "new RatExpr( " << mpz_get_si( num ) << ", " << mpz_get_si( den ) << " );" << std::endl; + indent( os, ind ); + os << incString.c_str() << std::endl; + } + break; + case SYMS_EXPR: + { + //if it is a variable, simply write it to buffer + if( is_var( ((SymSExpr*)code)->s ) ) + { + indent( os, ind ); + os << retModString.c_str(); + write_variable( ((SymSExpr*)code)->s.c_str(), os ); + os << ";" << std::endl; + } + else //else must look at symbol lookup table + { + std::string var; + get_var_name( ((SymSExpr*)code)->s, var ); + indent( os, ind ); + os << retModString.c_str() << "e_" << var.c_str() << ";" << std::endl; + add_global_sym( var ); + } + indent( os, ind ); + os << incString.c_str() << std::endl; + } + break; + default: + switch( code->getop() ) + { case APP: { //collect the arguments @@ -403,7 +403,7 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r //os << expr.c_str() << "->dec();" << std::endl; } } - break; + break; case MATCH: { //calculate the value for the expression @@ -565,13 +565,13 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r if( retModStr!=NULL ){ indent( os, ind ); os << retModString.c_str() << expr.c_str() << ";" << std::endl; - indent( os, ind ); + indent( os, ind ); os << incString.c_str() << std::endl; } write_dec( expr, os, ind ); } break; - case IFMARKED: + case IFMARKED: { //calculate the value for the expression std::string expr; @@ -585,10 +585,10 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r os << "}else{" << std::endl; write_code( ((CExpr*)code)->kids[2], os, ind+1, retModStr ); indent( os, ind ); - os << "}" << std::endl; - //clean up memory - write_dec( expr, os, ind ); - } + os << "}" << std::endl; + //clean up memory + write_dec( expr, os, ind ); + } break; #else case MARKVAR: @@ -612,7 +612,7 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r if( retModStr!=NULL ){ indent( os, ind ); os << retModString.c_str() << expr.c_str() << ";" << std::endl; - indent( os, ind ); + indent( os, ind ); os << incString.c_str() << std::endl; } write_dec( expr, os, ind ); @@ -631,12 +631,12 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r write_code( ((CExpr*)code)->kids[3], os, ind+1, retModStr ); indent( os, ind ); os << "}" << std::endl; - //clean up memory + //clean up memory write_dec( expr1, os, ind ); write_dec( expr2, os, ind ); } break; - case IFMARKED: + case IFMARKED: { //calculate the value for the expression std::string expr; @@ -651,10 +651,10 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r os << "}else{" << std::endl; write_code( ((CExpr*)code)->kids[3], os, ind+1, retModStr ); indent( os, ind ); - os << "}" << std::endl; - //clean up memory - write_dec( expr, os, ind ); - } + os << "}" << std::endl; + //clean up memory + write_dec( expr, os, ind ); + } break; #endif case ADD: @@ -709,8 +709,8 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r write_dec( expr2, os, ind ); } break; - case NEG: - { + case NEG: + { //calculate the value for the first expression std::string expr1; write_expr( ((CExpr*)code)->kids[0], os, ind, expr1 ); @@ -726,9 +726,9 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r indent( os, ind+1 ); os << "mpz_neg( " << ss.str().c_str() << ", ((IntExpr*)" << expr1.c_str() << "->followDefs())->n );" << std::endl; indent( os, ind+1 ); - os << retModString.c_str() << "new IntExpr(" << ss.str().c_str() << ");" << std::endl; + os << retModString.c_str() << "new IntExpr(" << ss.str().c_str() << ");" << std::endl; indent( os, ind ); - os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl; + os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl; indent( os, ind+1 ); os << "mpq_t " << ss.str().c_str() << ";" << std::endl; indent( os, ind+1 ); @@ -736,55 +736,55 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r indent( os, ind+1 ); os << "mpq_neg( " << ss.str().c_str() << ", ((RatExpr*)" << expr1.c_str() << "->followDefs())->n );" << std::endl; indent( os, ind+1 ); - os << retModString.c_str() << "new RatExpr(" << ss.str().c_str() << ");" << std::endl; + os << retModString.c_str() << "new RatExpr(" << ss.str().c_str() << ");" << std::endl; indent( os, ind ); - os << "}" << std::endl; - //clean up memory - write_dec( expr1, os, ind ); - } - break; - case IFNEG: - case IFZERO: - { + os << "}" << std::endl; + //clean up memory + write_dec( expr1, os, ind ); + } + break; + case IFNEG: + case IFZERO: + { std::string expr1; - write_expr( ((CExpr*)code)->kids[0], os, ind, expr1 ); + write_expr( ((CExpr*)code)->kids[0], os, ind, expr1 ); indent( os, ind ); - os << "if( " << expr1.c_str() << "->followDefs()->getclass()==INT_EXPR ){" << std::endl; - indent( os, ind+1 ); - os << "if( mpz_sgn( ((IntExpr *)" << expr1.c_str() << "->followDefs())->n ) "; - if( code->getop()==IFNEG ) - os << "<"; - else - os << "=="; - os << " 0 ){" << std::endl; - write_code( ((CExpr*)code)->kids[1], os, ind+2, retModStr ); - indent( os, ind+1 ); - os << "}else{" << std::endl; - write_code( ((CExpr*)code)->kids[2], os, ind+2, retModStr ); - indent( os, ind+1 ); - os << "}" << std::endl; + os << "if( " << expr1.c_str() << "->followDefs()->getclass()==INT_EXPR ){" << std::endl; + indent( os, ind+1 ); + os << "if( mpz_sgn( ((IntExpr *)" << expr1.c_str() << "->followDefs())->n ) "; + if( code->getop()==IFNEG ) + os << "<"; + else + os << "=="; + os << " 0 ){" << std::endl; + write_code( ((CExpr*)code)->kids[1], os, ind+2, retModStr ); + indent( os, ind+1 ); + os << "}else{" << std::endl; + write_code( ((CExpr*)code)->kids[2], os, ind+2, retModStr ); + indent( os, ind+1 ); + os << "}" << std::endl; indent( os, ind ); - os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl; - indent( os, ind+1 ); - os << "if( mpq_sgn( ((RatExpr *)" << expr1.c_str() << "->followDefs())->n ) "; - if( code->getop()==IFNEG ) - os << "<"; - else - os << "=="; - os << " 0 ){" << std::endl; - write_code( ((CExpr*)code)->kids[1], os, ind+2, retModStr ); - indent( os, ind+1 ); - os << "}else{" << std::endl; - write_code( ((CExpr*)code)->kids[2], os, ind+2, retModStr ); - indent( os, ind+1 ); - os << "}" << std::endl; + os << "}else if( " << expr1.c_str() << "->followDefs()->getclass()==RAT_EXPR ){" << std::endl; + indent( os, ind+1 ); + os << "if( mpq_sgn( ((RatExpr *)" << expr1.c_str() << "->followDefs())->n ) "; + if( code->getop()==IFNEG ) + os << "<"; + else + os << "=="; + os << " 0 ){" << std::endl; + write_code( ((CExpr*)code)->kids[1], os, ind+2, retModStr ); + indent( os, ind+1 ); + os << "}else{" << std::endl; + write_code( ((CExpr*)code)->kids[2], os, ind+2, retModStr ); + indent( os, ind+1 ); + os << "}" << std::endl; indent( os, ind ); - os << "}" << std::endl; - //clean up memory - write_dec( expr1, os, ind ); - } - break; - case RUN:/*?*/break; + os << "}" << std::endl; + //clean up memory + write_dec( expr1, os, ind ); + } + break; + case RUN:/*?*/break; case PI:/*?*/break; case LAM:/*?*/break; case TYPE:/*?*/break; @@ -793,16 +793,16 @@ void sccwriter::write_code( Expr* code, std::ostream& os, int ind, const char* r case MPZ:/*?*/break; case PROG:/*?*/break; case PROGVARS:/*?*/break; - case PAT:/*?*/break; - } - break; - } -} - -void sccwriter::write_args( CExpr* code, std::ostream& os, int ind, int childCounter, - std::vector< std::string >& args, int opts ) -{ - bool encounterCase = false; + case PAT:/*?*/break; + } + break; + } +} + +void sccwriter::write_args( CExpr* code, std::ostream& os, int ind, int childCounter, + std::vector< std::string >& args, int opts ) +{ + bool encounterCase = false; while( code->kids[childCounter] && (!encounterCase || code->kids[childCounter]->getop()==CASE ) ) { @@ -819,68 +819,68 @@ void sccwriter::write_args( CExpr* code, std::ostream& os, int ind, int childCou args.push_back( expr ); } childCounter++; - } -} - -void sccwriter::write_expr( Expr* code, std::ostream& os, int ind, std::string& expr, int opts ) -{ - if( code->getclass()==SYMS_EXPR && is_var( ((SymSExpr*)code)->s ) ) - { - get_var_name( ((SymSExpr*)code)->s, expr ); - indent( os, ind ); - os << expr.c_str() << "->inc();" << std::endl; - } - else - { + } +} + +void sccwriter::write_expr( Expr* code, std::ostream& os, int ind, std::string& expr, int opts ) +{ + if( code->getclass()==SYMS_EXPR && is_var( ((SymSExpr*)code)->s ) ) + { + get_var_name( ((SymSExpr*)code)->s, expr ); + indent( os, ind ); + os << expr.c_str() << "->inc();" << std::endl; + } + else + { std::ostringstream ss; ss << "e" << exprCount; - exprCount++; - //declare the expression - indent( os, ind ); - if( code->getclass()==SYMS_EXPR && !is_var( ((SymSExpr*)code)->s ) ) - { - os << "static "; - } - os << "Expr* " << ss.str().c_str() << ";" << std::endl; - //write the expression + exprCount++; + //declare the expression + indent( os, ind ); + if( code->getclass()==SYMS_EXPR && !is_var( ((SymSExpr*)code)->s ) ) + { + os << "static "; + } + os << "Expr* " << ss.str().c_str() << ";" << std::endl; + //write the expression std::ostringstream ss2; ss2 << ss.str().c_str(); - write_code( code, os, ind, ss2.str().c_str(), opts ); - - //if is not a sym expression, then decrement the expression and return null - if( opts&opt_write_check_sym_expr ) + write_code( code, os, ind, ss2.str().c_str(), opts ); + + //if is not a sym expression, then decrement the expression and return null + if( opts&opt_write_check_sym_expr ) { indent( os, ind ); os << "if (" << expr.c_str() << "->getclass() != SYM_EXPR) {" << std::endl; indent( os, ind+1 ); os << "exit( 1 );" << std::endl; indent( os, ind ); - os << "}" << std::endl; - } - - expr = std::string( ss.str().c_str() ); - vars.push_back( expr ); - } - //increment the counter for memory management - //indent( os, ind ); - //os << expr.c_str() << "->inc();" << std::endl; -} - -void sccwriter::write_dec( const std::string& expr, std::ostream& os, int ind ) -{ - bool wd = true; - if( wd ) - { - indent( os, ind ); - os << expr.c_str() << "->dec();" << std::endl; - } -} - -void sccwriter::debug_write_code( Expr* code, std::ostream& os, int ind ) -{ - indent( os, ind ); - switch( code->getclass() ) - { + os << "}" << std::endl; + } + + expr = std::string( ss.str().c_str() ); + vars.push_back( expr ); + } + //increment the counter for memory management + //indent( os, ind ); + //os << expr.c_str() << "->inc();" << std::endl; +} + +void sccwriter::write_dec( const std::string& expr, std::ostream& os, int ind ) +{ + bool wd = true; + if( wd ) + { + indent( os, ind ); + os << expr.c_str() << "->dec();" << std::endl; + } +} + +void sccwriter::debug_write_code( Expr* code, std::ostream& os, int ind ) +{ + indent( os, ind ); + switch( code->getclass() ) + { case INT_EXPR: os << "int_expr"; break; @@ -890,12 +890,12 @@ void sccwriter::debug_write_code( Expr* code, std::ostream& os, int ind ) case SYM_EXPR: os << "sym_expr"; break; - case SYMS_EXPR: - os << "syms_expr: " << ((SymSExpr*)code)->s.c_str(); - break; - default: - switch( code->getop() ) - { + case SYMS_EXPR: + os << "syms_expr: " << ((SymSExpr*)code)->s.c_str(); + break; + default: + switch( code->getop() ) + { case APP: os << "app"; break; @@ -920,9 +920,9 @@ void sccwriter::debug_write_code( Expr* code, std::ostream& os, int ind ) case PROG: os << "prog"; break; - case PROGVARS: - os << "progvars"; - break; + case PROGVARS: + os << "progvars"; + break; case MATCH: os << "match"; break; @@ -953,25 +953,25 @@ void sccwriter::debug_write_code( Expr* code, std::ostream& os, int ind ) case MARKVAR: os << "markvar"; break; - case IFMARKED: - os << "ifmarked"; - break; - case COMPARE: - os << "compare"; - break; - default: - os << "???"; - break; - } - } - os << std::endl; - if( code->getop()!=0 ) - { - CExpr* ce = (CExpr*)code; - int counter = 0; - while( ce->kids[counter] ){ - debug_write_code( ce->kids[counter], os, ind+1 ); - counter++; - } - } -} + case IFMARKED: + os << "ifmarked"; + break; + case COMPARE: + os << "compare"; + break; + default: + os << "???"; + break; + } + } + os << std::endl; + if( code->getop()!=0 ) + { + CExpr* ce = (CExpr*)code; + int counter = 0; + while( ce->kids[counter] ){ + debug_write_code( ce->kids[counter], os, ind+1 ); + counter++; + } + } +} diff --git a/proofs/lfsc_checker/sccwriter.h b/proofs/lfsc_checker/sccwriter.h index f8922934f..bd9732579 100644 --- a/proofs/lfsc_checker/sccwriter.h +++ b/proofs/lfsc_checker/sccwriter.h @@ -1,86 +1,86 @@ -#ifndef SCC_WRITER_H -#define SCC_WRITER_H - -#include "expr.h" -#include -#include "check.h" - -enum -{ - opt_write_case_body = 0x00000001, - opt_write_check_sym_expr = 0x00000002, - opt_write_add_args = 0x000000004, - opt_write_no_inc = 0x00000008, - - opt_write_call_debug = 0x00000010, - opt_write_nested_app = 0x00000020, -}; - -class sccwriter -{ -private: - //options - int options; - //programs to write to file - symmap progs; - //list of indicies in progs - std::vector< Expr* > progPtrs; - std::vector< std::string > progNames; - int currProgram; - //current variables in the scope - std::vector< std::string > vars; - //global variables stored for lookups - std::vector< std::string > globalSyms; - //symbols that must be dec'ed - std::vector< std::string > decSyms; - //get program - CExpr* get_prog( int n ) { return (CExpr*)progs[ progNames[n] ]; } - //get index for string - int get_prog_index_by_expr( Expr* e ); - int get_prog_index( const std::string& str ); - //is variable in current scope - bool is_var( const std::string& str ); - //add global sym - void add_global_sym( const std::string& str ); - //expression count - static int exprCount; - //string count - static int strCount; - //args count - static int argsCount; - //num count - static int rnumCount; - //indent - static void indent( std::ostream& os, int ind ); - //write function header - void write_function_header( std::ostream& os, int index, int opts = 0 ); - void write_code( Expr* code, std::ostream& os, int ind, const char* retModStr, int opts = 0 ); - //write all children starting at child counter to stream, store in Expr* e_...e_; - void write_args( CExpr* code, std::ostream& os, int ind, int childCounter, std::vector< std::string >& args, int opts = 0 ); - //write expression - store result of code into e_ for some Expr* e_; - void write_expr( Expr* code, std::ostream& os, int ind, std::string& expr, int opts = 0 ); - //write variable - void write_variable( const std::string& n, std::ostream& os ); - //get function name - void get_function_name( const std::string& pname, std::string& fname ); - //get the variable name - void get_var_name( const std::string& n, std::string& nn ); - //write dec - void write_dec( const std::string& expr, std::ostream& os, int ind ); -public: - sccwriter( int opts = 0 ) : options( opts ){} - virtual ~sccwriter(){} - - void add_scc( const std::string& pname, Expr* exp ) { - //progs.push_back( std::pair< std::string, CExpr* >( pname, exp ) ); - progs[pname] = exp; - progPtrs.push_back( exp ); - progNames.push_back( pname ); - } - - void write_file(); - //write code - static void debug_write_code( Expr* code, std::ostream& os, int ind ); -}; - -#endif +#ifndef SCC_WRITER_H +#define SCC_WRITER_H + +#include "expr.h" +#include +#include "check.h" + +enum +{ + opt_write_case_body = 0x00000001, + opt_write_check_sym_expr = 0x00000002, + opt_write_add_args = 0x000000004, + opt_write_no_inc = 0x00000008, + + opt_write_call_debug = 0x00000010, + opt_write_nested_app = 0x00000020, +}; + +class sccwriter +{ +private: + //options + int options; + //programs to write to file + symmap progs; + //list of indicies in progs + std::vector< Expr* > progPtrs; + std::vector< std::string > progNames; + int currProgram; + //current variables in the scope + std::vector< std::string > vars; + //global variables stored for lookups + std::vector< std::string > globalSyms; + //symbols that must be dec'ed + std::vector< std::string > decSyms; + //get program + CExpr* get_prog( int n ) { return (CExpr*)progs[ progNames[n] ]; } + //get index for string + int get_prog_index_by_expr( Expr* e ); + int get_prog_index( const std::string& str ); + //is variable in current scope + bool is_var( const std::string& str ); + //add global sym + void add_global_sym( const std::string& str ); + //expression count + static int exprCount; + //string count + static int strCount; + //args count + static int argsCount; + //num count + static int rnumCount; + //indent + static void indent( std::ostream& os, int ind ); + //write function header + void write_function_header( std::ostream& os, int index, int opts = 0 ); + void write_code( Expr* code, std::ostream& os, int ind, const char* retModStr, int opts = 0 ); + //write all children starting at child counter to stream, store in Expr* e_...e_; + void write_args( CExpr* code, std::ostream& os, int ind, int childCounter, std::vector< std::string >& args, int opts = 0 ); + //write expression - store result of code into e_ for some Expr* e_; + void write_expr( Expr* code, std::ostream& os, int ind, std::string& expr, int opts = 0 ); + //write variable + void write_variable( const std::string& n, std::ostream& os ); + //get function name + void get_function_name( const std::string& pname, std::string& fname ); + //get the variable name + void get_var_name( const std::string& n, std::string& nn ); + //write dec + void write_dec( const std::string& expr, std::ostream& os, int ind ); +public: + sccwriter( int opts = 0 ) : options( opts ){} + virtual ~sccwriter(){} + + void add_scc( const std::string& pname, Expr* exp ) { + //progs.push_back( std::pair< std::string, CExpr* >( pname, exp ) ); + progs[pname] = exp; + progPtrs.push_back( exp ); + progNames.push_back( pname ); + } + + void write_file(); + //write code + static void debug_write_code( Expr* code, std::ostream& os, int ind ); +}; + +#endif diff --git a/proofs/signatures/ex_bv.plf b/proofs/signatures/ex_bv.plf index 02cadaeab..ae585e455 100755 --- a/proofs/signatures/ex_bv.plf +++ b/proofs/signatures/ex_bv.plf @@ -1,57 +1,57 @@ -; a = b ^ a = 00000 ^ b = 11111 is UNSAT - -(check -(% a var_bv -(% b var_bv -(% f1 (th_holds (= BitVec (a_var_bv a) (a_var_bv b))) -(% f2 (th_holds (= BitVec (a_var_bv a) (a_bv (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn)))))))) -(% f3 (th_holds (= BitVec (a_var_bv b) (a_bv (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn)))))))) -(: (holds cln) - -(decl_bv_atom_var 5 a (\ ba1 -(decl_bv_atom_var 5 b (\ ba2 -(decl_bv_atom_const _ (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn))))) (\ c (\ ba3 -(decl_bv_atom_const _ (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn))))) (\ d (\ ba4 - -(decl_atom (bblast a 4) (\ v1 (\ a1 -(decl_atom (bblast b 4) (\ v2 (\ a2 - -; bitblasting terms -(th_let_pf _ (bv_bbl_var _ _ _ ba1) (\ bt1 -(th_let_pf _ (bv_bbl_var _ _ _ ba2) (\ bt2 -(th_let_pf _ (bv_bbl_const _ _ _ _ ba3) (\ bt3 -(th_let_pf _ (bv_bbl_const _ _ _ _ ba4) (\ bt4 - -; bitblasting formulas -(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt2) (\ bf1 -(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt3) (\ bf2 -(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt2 bt4) (\ bf3 - -; CNFication -; a.4 V ~b.4 -(satlem _ _ -(asf _ _ _ a1 (\ l1 -(ast _ _ _ a2 (\ l2 -(clausify_false - (contra _ (impl_elim _ _ l2 (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f1 bf1)))) l1) ; notice at the intermost we impl_elim, which converts from atom to bit-blasting representation -))))) (\ C2 - -; ~a.4 -(satlem _ _ -(ast _ _ _ a1 (\ l1 -(clausify_false - (impl_elim _ _ l1 (iff_elim_1 _ _ (and_elim_1 _ _ (impl_elim _ _ f2 bf2)))) -))) (\ C3 - -; b.4 -(satlem _ _ -(asf _ _ _ a2 (\ l2 -(clausify_false - (contra _ (impl_elim _ _ truth (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f3 bf3)))) l2) -))) (\ C6 - - -(satlem_simplify _ _ _ -(R _ _ (R _ _ C6 C2 v2) C3 v1) (\ x x)) - +; a = b ^ a = 00000 ^ b = 11111 is UNSAT + +(check +(% a var_bv +(% b var_bv +(% f1 (th_holds (= BitVec (a_var_bv a) (a_var_bv b))) +(% f2 (th_holds (= BitVec (a_var_bv a) (a_bv (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn)))))))) +(% f3 (th_holds (= BitVec (a_var_bv b) (a_bv (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn)))))))) +(: (holds cln) + +(decl_bv_atom_var 5 a (\ ba1 +(decl_bv_atom_var 5 b (\ ba2 +(decl_bv_atom_const _ (bvc b0 (bvc b0 (bvc b0 (bvc b0 (bvc b0 bvn))))) (\ c (\ ba3 +(decl_bv_atom_const _ (bvc b1 (bvc b1 (bvc b1 (bvc b1 (bvc b1 bvn))))) (\ d (\ ba4 + +(decl_atom (bblast a 4) (\ v1 (\ a1 +(decl_atom (bblast b 4) (\ v2 (\ a2 + +; bitblasting terms +(th_let_pf _ (bv_bbl_var _ _ _ ba1) (\ bt1 +(th_let_pf _ (bv_bbl_var _ _ _ ba2) (\ bt2 +(th_let_pf _ (bv_bbl_const _ _ _ _ ba3) (\ bt3 +(th_let_pf _ (bv_bbl_const _ _ _ _ ba4) (\ bt4 + +; bitblasting formulas +(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt2) (\ bf1 +(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt1 bt3) (\ bf2 +(th_let_pf _ (bv_bbl_eq _ _ _ _ _ bt2 bt4) (\ bf3 + +; CNFication +; a.4 V ~b.4 +(satlem _ _ +(asf _ _ _ a1 (\ l1 +(ast _ _ _ a2 (\ l2 +(clausify_false + (contra _ (impl_elim _ _ l2 (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f1 bf1)))) l1) ; notice at the intermost we impl_elim, which converts from atom to bit-blasting representation +))))) (\ C2 + +; ~a.4 +(satlem _ _ +(ast _ _ _ a1 (\ l1 +(clausify_false + (impl_elim _ _ l1 (iff_elim_1 _ _ (and_elim_1 _ _ (impl_elim _ _ f2 bf2)))) +))) (\ C3 + +; b.4 +(satlem _ _ +(asf _ _ _ a2 (\ l2 +(clausify_false + (contra _ (impl_elim _ _ truth (iff_elim_2 _ _ (and_elim_1 _ _ (impl_elim _ _ f3 bf3)))) l2) +))) (\ C6 + + +(satlem_simplify _ _ _ +(R _ _ (R _ _ C6 C2 v2) C3 v1) (\ x x)) + ))))))))))))))))))))))))))))))))))))))))))) \ No newline at end of file diff --git a/proofs/signatures/th_bv.plf b/proofs/signatures/th_bv.plf index 3fb9d1356..0fb50f8cf 100755 --- a/proofs/signatures/th_bv.plf +++ b/proofs/signatures/th_bv.plf @@ -1,145 +1,145 @@ -; "bitvec" is a term of type "sort" -(declare BitVec sort) - -; bit type -(declare bit type) -(declare b0 bit) -(declare b1 bit) - -; bit vector type -(declare bv type) -(declare bvn bv) -(declare bvc (! b bit (! v bv bv))) -; a bv constant term -(declare a_bv (! v bv (term BitVec))) - -; calculate the length of a bitvector -(program bv_len ((v bv)) mpz - (match v - (bvn 0) - ((bvc b v') (mp_add (bv_len v') 1)))) - -; a bv variable -(declare var_bv type) -; a bv variable term -(declare a_var_bv (! v var_bv (term BitVec))) - - -; bit vector operators -(define bvoper (! x (term BitVec) - (! y (term BitVec) - (term BitVec)))) -(declare bvand bvoper) -(declare bvadd bvoper) -;.... - -; all bit-vector terms are mapped with "bv_atom" to: -; - a simply-typed term of type "var_bv", which is necessary for bit-blasting -; - a integer size -(declare bv_atom (! x (term BitVec) (! y var_bv (! n mpz type)))) - -(declare decl_bv_atom_var (! n mpz ; must be specified - (! x var_bv - (! p (! u (bv_atom (a_var_bv x) x n) - (holds cln)) - (holds cln))))) - -(declare decl_bv_atom_const (! n mpz - (! v bv - (! s (^ (bv_len v) n) - (! p (! w var_bv - (! u (bv_atom (a_bv v) w n) - (holds cln))) - (holds cln)))))) - - -; other terms here? - - -; bit blasted terms -(declare bblt type) -(declare bbltn bblt) -(declare bbltc (! f formula (! v bblt bblt))) - -; (bblast_term x y) means term x corresponds to bit level interpretation y -(declare bblast_term (! x (term BitVec) (! y bblt formula))) - -; a predicate to represent the n^th bit of a bitvector term -(declare bblast (! x var_bv (! n mpz formula))) - - -; bit blast constant -(program bblast_const ((v bv) (n mpz)) bblt - (mp_ifneg n (match v (bvn bbltn) - (default (fail bblt))) - (match v ((bvc b v') (bbltc (match b (b0 false) (b1 true)) (bblast_const v' (mp_add n (~ 1))))) - (default (fail bblt))))) - -(declare bv_bbl_const (! n mpz - (! v bv - (! x var_bv - (! f bblt - (! u (bv_atom (a_bv v) x n) - (! c (^ (bblast_const v (mp_add n (~ 1))) f) - (th_holds (bblast_term (a_bv v) f))))))))) - -; bit blast variable -(program bblast_var ((x var_bv) (n mpz)) bblt - (mp_ifneg n bbltn - (bbltc (bblast x n) (bblast_var x (mp_add n (~ 1)))))) - -(declare bv_bbl_var (! n mpz - (! x var_bv - (! f bblt - (! u (bv_atom (a_var_bv x) x n) - (! c (^ (bblast_var x (mp_add n (~ 1))) f) - (th_holds (bblast_term (a_var_bv x) f)))))))) - -; bit blast x = y -; for x,y of size n, it will return a conjuction (x.{n-1} = y.{n-1} ^ ( ... ^ (x.0 = y.0 ^ true))) -(program bblast_eq ((x bblt) (y bblt)) formula - (match x - (bbltn (match y (bbltn true) (default (fail formula)))) - ((bbltc fx x') (match y - (bbltn (fail formula)) - ((bbltc fy y') (and (iff fx fy) (bblast_eq x' y'))))))) - -(declare bv_bbl_eq (! x (term BitVec) - (! y (term BitVec) - (! fx bblt - (! fy bblt - (! f formula - (! ux (th_holds (bblast_term x fx)) - (! uy (th_holds (bblast_term y fy)) - (! c (^ (bblast_eq fx fy) f) - (th_holds (impl (= BitVec x y) f))))))))))) - - -; rewrite rule : -; x + y = y + x -(declare bvadd_symm (! x (term BitVec) - (! y (term BitVec) - (! x' var_bv - (! y' var_bv - (! n mpz - (! ux (bv_atom x x' n) - (! uy (bv_atom y y' n) - (th_holds (= BitVec (bvadd x y) (bvadd y x))))))))))) - - - -; necessary? -(program calc_bvand ((a bv) (b bv)) bv - (match a - (bvn (match b (bvn bvn) (default (fail bv)))) - ((bvc ba a') (match b - ((bvc bb b') (bvc (match ba (b0 b0) (b1 bb)) (calc_bvand a' b'))) - (default (fail bv)))))) - -; rewrite rule (w constants) : -; a & b = c -(declare bvand_const (! c bv - (! a bv - (! b bv - (! u (^ (calc_bvand a b) c) +; "bitvec" is a term of type "sort" +(declare BitVec sort) + +; bit type +(declare bit type) +(declare b0 bit) +(declare b1 bit) + +; bit vector type +(declare bv type) +(declare bvn bv) +(declare bvc (! b bit (! v bv bv))) +; a bv constant term +(declare a_bv (! v bv (term BitVec))) + +; calculate the length of a bitvector +(program bv_len ((v bv)) mpz + (match v + (bvn 0) + ((bvc b v') (mp_add (bv_len v') 1)))) + +; a bv variable +(declare var_bv type) +; a bv variable term +(declare a_var_bv (! v var_bv (term BitVec))) + + +; bit vector operators +(define bvoper (! x (term BitVec) + (! y (term BitVec) + (term BitVec)))) +(declare bvand bvoper) +(declare bvadd bvoper) +;.... + +; all bit-vector terms are mapped with "bv_atom" to: +; - a simply-typed term of type "var_bv", which is necessary for bit-blasting +; - a integer size +(declare bv_atom (! x (term BitVec) (! y var_bv (! n mpz type)))) + +(declare decl_bv_atom_var (! n mpz ; must be specified + (! x var_bv + (! p (! u (bv_atom (a_var_bv x) x n) + (holds cln)) + (holds cln))))) + +(declare decl_bv_atom_const (! n mpz + (! v bv + (! s (^ (bv_len v) n) + (! p (! w var_bv + (! u (bv_atom (a_bv v) w n) + (holds cln))) + (holds cln)))))) + + +; other terms here? + + +; bit blasted terms +(declare bblt type) +(declare bbltn bblt) +(declare bbltc (! f formula (! v bblt bblt))) + +; (bblast_term x y) means term x corresponds to bit level interpretation y +(declare bblast_term (! x (term BitVec) (! y bblt formula))) + +; a predicate to represent the n^th bit of a bitvector term +(declare bblast (! x var_bv (! n mpz formula))) + + +; bit blast constant +(program bblast_const ((v bv) (n mpz)) bblt + (mp_ifneg n (match v (bvn bbltn) + (default (fail bblt))) + (match v ((bvc b v') (bbltc (match b (b0 false) (b1 true)) (bblast_const v' (mp_add n (~ 1))))) + (default (fail bblt))))) + +(declare bv_bbl_const (! n mpz + (! v bv + (! x var_bv + (! f bblt + (! u (bv_atom (a_bv v) x n) + (! c (^ (bblast_const v (mp_add n (~ 1))) f) + (th_holds (bblast_term (a_bv v) f))))))))) + +; bit blast variable +(program bblast_var ((x var_bv) (n mpz)) bblt + (mp_ifneg n bbltn + (bbltc (bblast x n) (bblast_var x (mp_add n (~ 1)))))) + +(declare bv_bbl_var (! n mpz + (! x var_bv + (! f bblt + (! u (bv_atom (a_var_bv x) x n) + (! c (^ (bblast_var x (mp_add n (~ 1))) f) + (th_holds (bblast_term (a_var_bv x) f)))))))) + +; bit blast x = y +; for x,y of size n, it will return a conjuction (x.{n-1} = y.{n-1} ^ ( ... ^ (x.0 = y.0 ^ true))) +(program bblast_eq ((x bblt) (y bblt)) formula + (match x + (bbltn (match y (bbltn true) (default (fail formula)))) + ((bbltc fx x') (match y + (bbltn (fail formula)) + ((bbltc fy y') (and (iff fx fy) (bblast_eq x' y'))))))) + +(declare bv_bbl_eq (! x (term BitVec) + (! y (term BitVec) + (! fx bblt + (! fy bblt + (! f formula + (! ux (th_holds (bblast_term x fx)) + (! uy (th_holds (bblast_term y fy)) + (! c (^ (bblast_eq fx fy) f) + (th_holds (impl (= BitVec x y) f))))))))))) + + +; rewrite rule : +; x + y = y + x +(declare bvadd_symm (! x (term BitVec) + (! y (term BitVec) + (! x' var_bv + (! y' var_bv + (! n mpz + (! ux (bv_atom x x' n) + (! uy (bv_atom y y' n) + (th_holds (= BitVec (bvadd x y) (bvadd y x))))))))))) + + + +; necessary? +(program calc_bvand ((a bv) (b bv)) bv + (match a + (bvn (match b (bvn bvn) (default (fail bv)))) + ((bvc ba a') (match b + ((bvc bb b') (bvc (match ba (b0 b0) (b1 bb)) (calc_bvand a' b'))) + (default (fail bv)))))) + +; rewrite rule (w constants) : +; a & b = c +(declare bvand_const (! c bv + (! a bv + (! b bv + (! u (^ (calc_bvand a b) c) (th_holds (= BitVec (bvand (a_bv a) (a_bv b)) (a_bv c)))))))) \ No newline at end of file diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp index 116debb7c..4167c3ad9 100644 --- a/src/theory/quantifiers/conjecture_generator.cpp +++ b/src/theory/quantifiers/conjecture_generator.cpp @@ -1,2180 +1,2180 @@ -/********************* */ -/*! \file conjecture_generator.cpp - ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief conjecture generator class - ** - **/ - -#include "theory/quantifiers/conjecture_generator.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers/options.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/trigger.h" -#include "theory/quantifiers/first_order_model.h" - -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; -using namespace std; - -namespace CVC4 { - -struct sortConjectureScore { - std::vector< int > d_scores; - bool operator() (unsigned i, unsigned j) { return d_scores[i]>d_scores[j]; } -}; - - -void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){ - if( index==n.getNumChildren() ){ - Assert( n.hasOperator() ); - if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){ - d_ops.push_back( n.getOperator() ); - d_op_terms.push_back( n ); - } - }else{ - d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 ); - } -} - -Node OpArgIndex::getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ) { - if( d_ops.empty() ){ - for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){ - std::map< TNode, Node >::iterator itf = s->d_ground_eqc_map.find( it->first ); - if( itf!=s->d_ground_eqc_map.end() ){ - args.push_back( itf->second ); - Node n = it->second.getGroundTerm( s, args ); - args.pop_back(); - if( !n.isNull() ){ - return n; - } - } - } - return Node::null(); - }else{ - std::vector< TNode > args2; - args2.push_back( d_ops[0] ); - args2.insert( args2.end(), args.begin(), args.end() ); - return NodeManager::currentNM()->mkNode( d_op_terms[0].getKind(), args2 ); - } -} - -void OpArgIndex::getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ) { - terms.insert( terms.end(), d_op_terms.begin(), d_op_terms.end() ); - for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){ - if( s->isGroundEqc( it->first ) ){ - it->second.getGroundTerms( s, terms ); - } - } -} - - - -ConjectureGenerator::ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ), -d_notify( *this ), -d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee", false), -d_ee_conjectures( c ){ - d_fullEffortCount = 0; - d_uequalityEngine.addFunctionKind( kind::APPLY_UF ); - d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR ); - -} - -void ConjectureGenerator::eqNotifyNewClass( TNode t ){ - Trace("thm-ee-debug") << "UEE : new equivalence class " << t << std::endl; - d_upendingAdds.push_back( t ); -} - -void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) { - //get maintained representatives - TNode rt1 = t1; - TNode rt2 = t2; - std::map< Node, EqcInfo* >::iterator it1 = d_eqc_info.find( t1 ); - if( it1!=d_eqc_info.end() && !it1->second->d_rep.get().isNull() ){ - rt1 = it1->second->d_rep.get(); - } - std::map< Node, EqcInfo* >::iterator it2 = d_eqc_info.find( t2 ); - if( it2!=d_eqc_info.end() && !it2->second->d_rep.get().isNull() ){ - rt2 = it2->second->d_rep.get(); - } - Trace("thm-ee-debug") << "UEE : equality holds : " << t1 << " == " << t2 << std::endl; - Trace("thm-ee-debug") << " ureps : " << rt1 << " == " << rt2 << std::endl; - Trace("thm-ee-debug") << " relevant : " << d_pattern_is_relevant[rt1] << " " << d_pattern_is_relevant[rt2] << std::endl; - Trace("thm-ee-debug") << " normal : " << d_pattern_is_normal[rt1] << " " << d_pattern_is_normal[rt2] << std::endl; - Trace("thm-ee-debug") << " size : " << d_pattern_fun_sum[rt1] << " " << d_pattern_fun_sum[rt2] << std::endl; - - if( isUniversalLessThan( rt2, rt1 ) ){ - EqcInfo * ei; - if( it1==d_eqc_info.end() ){ - ei = getOrMakeEqcInfo( t1, true ); - }else{ - ei = it1->second; - } - ei->d_rep = t2; - } -} - -void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) { - -} - -void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { - Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl; - -} - - -ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){ - -} - -ConjectureGenerator::EqcInfo* ConjectureGenerator::getOrMakeEqcInfo( TNode n, bool doMake ) { - //Assert( getUniversalRepresentative( n )==n ); - std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n ); - if( eqc_i!=d_eqc_info.end() ){ - return eqc_i->second; - }else if( doMake ){ - EqcInfo* ei = new EqcInfo( d_quantEngine->getSatContext() ); - d_eqc_info[n] = ei; - return ei; - }else{ - return NULL; - } -} - -void ConjectureGenerator::setUniversalRelevant( TNode n ) { - //add pattern information - registerPattern( n, n.getType() ); - d_urelevant_terms[n] = true; - for( unsigned i=0; i pending; - pending.insert( pending.end(), d_upendingAdds.begin(), d_upendingAdds.end() ); - d_upendingAdds.clear(); - for( unsigned i=0; i eq_terms; - //if occurs modulo equality at ground level, it is equivalent to representative of ground equality engine - TNode gt = getTermDatabase()->evaluateTerm( t ); - if( !gt.isNull() && gt!=t ){ - eq_terms.push_back( gt ); - } - //get all equivalent terms based on theorem database - d_thm_index.getEquivalentTerms( t, eq_terms ); - if( !eq_terms.empty() ){ - Trace("thm-ee-add") << "UEE : Based on ground EE/theorem DB, it is equivalent to " << eq_terms.size() << " terms : " << std::endl; - //add equivalent terms as equalities to universal engine - for( unsigned i=0; i=d_pattern_fun_sum[eq_terms[i]] ) ){ - setUniversalRelevant( eq_terms[i] ); - assertEq = true; - } - } - if( assertEq ){ - Node exp; - d_uequalityEngine.assertEquality( t.eqNode( eq_terms[i] ), true, exp ); - }else{ - Trace("thm-ee-no-add") << "Do not add : " << t << " == " << eq_terms[i] << std::endl; - } - } - }else{ - Trace("thm-ee-add") << "UEE : No equivalent terms." << std::endl; - } - } - } - } - } - - if( d_uequalityEngine.hasTerm( n ) ){ - Node r = d_uequalityEngine.getRepresentative( n ); - EqcInfo * ei = getOrMakeEqcInfo( r ); - if( ei && !ei->d_rep.get().isNull() ){ - return ei->d_rep.get(); - }else{ - return r; - } - }else{ - return n; - } -} - -Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) { - Assert( !tn.isNull() ); - while( d_free_var[tn].size()<=i ){ - std::stringstream oss; - oss << tn; - std::string typ_name = oss.str(); - while( typ_name[0]=='(' ){ - typ_name.erase( typ_name.begin() ); - } - std::stringstream os; - os << typ_name[0] << i; - Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn ); - d_free_var_num[x] = d_free_var[tn].size(); - d_free_var[tn].push_back( x ); - } - return d_free_var[tn][i]; -} - - - -Node ConjectureGenerator::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ) { - if( n.getKind()==BOUND_VARIABLE ){ - std::map< TNode, TNode >::iterator it = subs.find( n ); - if( it==subs.end() ){ - TypeNode tn = n.getType(); - //allocate variable - unsigned vn = var_count[tn]; - var_count[tn]++; - subs[n] = getFreeVar( tn, vn ); - return subs[n]; - }else{ - return it->second; - } - }else{ - std::vector< Node > children; - if( n.getKind()!=EQUAL ){ - if( n.hasOperator() ){ - TNode op = n.getOperator(); - if( !d_tge.isRelevantFunc( op ) ){ - return Node::null(); - } - children.push_back( op ); - }else{ - return Node::null(); - } - } - for( unsigned i=0; imkNode( n.getKind(), children ); - } -} - -bool ConjectureGenerator::isHandledTerm( TNode n ){ - return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM ); -} - -Node ConjectureGenerator::getGroundEqc( TNode r ) { - std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r ); - return it!=d_ground_eqc_map.end() ? it->second : Node::null(); -} - -bool ConjectureGenerator::isGroundEqc( TNode r ) { - return d_ground_eqc_map.find( r )!=d_ground_eqc_map.end(); -} - -bool ConjectureGenerator::isGroundTerm( TNode n ) { - return std::find( d_ground_terms.begin(), d_ground_terms.end(), n )!=d_ground_terms.end(); -} - -bool ConjectureGenerator::needsCheck( Theory::Effort e ) { - // synchonized with instantiation engine - return d_quantEngine->getInstWhenNeedsCheck( e ); -} - -bool ConjectureGenerator::hasEnumeratedUf( Node n ) { - if( options::conjectureGenGtEnum()>0 ){ - std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() ); - if( it==d_uf_enum.end() ){ - d_uf_enum[n.getOperator()] = true; - std::vector< Node > lem; - getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem ); - if( !lem.empty() ){ - for( unsigned j=0; jaddLemma( lem[j], false ); - d_hasAddedLemma = true; - } - return false; - } - } - } - return true; -} - -void ConjectureGenerator::reset_round( Theory::Effort e ) { - -} - -void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) { - if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ - d_fullEffortCount++; - if( d_fullEffortCount%optFullCheckFrequency()==0 ){ - d_hasAddedLemma = false; - d_tge.d_cg = this; - double clSet = 0; - if( Trace.isOn("sg-engine") ){ - clSet = double(clock())/double(CLOCKS_PER_SEC); - Trace("sg-engine") << "---Conjecture Engine Round, effort = " << e << "---" << std::endl; - } - eq::EqualityEngine * ee = getEqualityEngine(); - d_conj_count = 0; - - Trace("sg-proc") << "Get eq classes..." << std::endl; - d_op_arg_index.clear(); - d_ground_eqc_map.clear(); - d_bool_eqc[0] = Node::null(); - d_bool_eqc[1] = Node::null(); - std::vector< TNode > eqcs; - d_em.clear(); - eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee ); - while( !eqcs_i.isFinished() ){ - TNode r = (*eqcs_i); - eqcs.push_back( r ); - if( r.getType().isBoolean() ){ - if( areEqual( r, getTermDatabase()->d_true ) ){ - d_ground_eqc_map[r] = getTermDatabase()->d_true; - d_bool_eqc[0] = r; - }else if( areEqual( r, getTermDatabase()->d_false ) ){ - d_ground_eqc_map[r] = getTermDatabase()->d_false; - d_bool_eqc[1] = r; - } - } - d_em[r] = eqcs.size(); - eq::EqClassIterator ieqc_i = eq::EqClassIterator( r, ee ); - while( !ieqc_i.isFinished() ){ - TNode n = (*ieqc_i); - if( getTermDatabase()->hasTermCurrent( n ) ){ - if( isHandledTerm( n ) ){ - d_op_arg_index[r].addTerm( this, n ); - } - } - ++ieqc_i; - } - ++eqcs_i; - } - Assert( !d_bool_eqc[0].isNull() ); - Assert( !d_bool_eqc[1].isNull() ); - d_urelevant_terms.clear(); - Trace("sg-proc") << "...done get eq classes" << std::endl; - - Trace("sg-proc") << "Determine ground EQC..." << std::endl; - bool success; - do{ - success = false; - for( unsigned i=0; i args; - Trace("sg-pat-debug") << "******* Get ground term for " << r << std::endl; - Node n; - if( getTermDatabase()->isInductionTerm( r ) ){ - n = d_op_arg_index[r].getGroundTerm( this, args ); - }else{ - n = r; - } - if( !n.isNull() ){ - Trace("sg-pat") << "Ground term for eqc " << r << " : " << std::endl; - Trace("sg-pat") << " " << n << std::endl; - d_ground_eqc_map[r] = n; - success = true; - }else{ - Trace("sg-pat-debug") << "...could not find ground term." << std::endl; - } - } - } - }while( success ); - //also get ground terms - d_ground_terms.clear(); - for( unsigned i=0; id_false ); - eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee ); - while( !eqc_i.isFinished() ){ - TNode n = (*eqc_i); - if( getTermDatabase()->hasTermCurrent( n ) && !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){ - if( firstTime ){ - Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl; - firstTime = false; - } - if( n.hasOperator() ){ - Trace("sg-gen-eqc") << " (" << n.getOperator(); - getTermDatabase()->computeArgReps( n ); - for( unsigned i=0; id_arg_reps[n].size(); i++ ){ - Trace("sg-gen-eqc") << " e" << d_em[getTermDatabase()->d_arg_reps[n][i]]; - } - Trace("sg-gen-eqc") << ") :: " << n << std::endl; - }else{ - Trace("sg-gen-eqc") << " " << n << std::endl; - } - } - ++eqc_i; - } - if( !firstTime ){ - Trace("sg-gen-eqc") << "}" << std::endl; - //print out ground term - std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r ); - if( it!=d_ground_eqc_map.end() ){ - Trace("sg-gen-eqc") << "- Ground term : " << it->second << std::endl; - } - } - } - } - - Trace("sg-proc") << "Compute relevant eqc..." << std::endl; - d_tge.d_relevant_eqc[0].clear(); - d_tge.d_relevant_eqc[1].clear(); - for( unsigned i=0; i::iterator it = d_ground_eqc_map.find( r ); - unsigned index = 1; - if( it==d_ground_eqc_map.end() ){ - index = 0; - } - //based on unproven conjectures? TODO - d_tge.d_relevant_eqc[index].push_back( r ); - } - Trace("sg-gen-tg-debug") << "Initial relevant eqc : "; - for( unsigned i=0; i provenConj; - quantifiers::FirstOrderModel* m = d_quantEngine->getModel(); - for( int i=0; igetNumAssertedQuantifiers(); i++ ){ - Node q = m->getAssertedQuantifier( i ); - Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl; - Node conjEq; - if( q[1].getKind()==EQUAL ){ - bool isSubsume = false; - bool inEe = false; - for( unsigned r=0; r<2; r++ ){ - TNode nl = q[1][r==0 ? 0 : 1]; - TNode nr = q[1][r==0 ? 1 : 0]; - Node eq = nl.eqNode( nr ); - if( r==1 || std::find( d_conjectures.begin(), d_conjectures.end(), q )==d_conjectures.end() ){ - //must make it canonical - std::map< TypeNode, unsigned > var_count; - std::map< TNode, TNode > subs; - Trace("sg-proc-debug") << "get canonical " << eq << std::endl; - eq = getCanonicalTerm( eq, var_count, subs ); - } - if( !eq.isNull() ){ - if( r==0 ){ - inEe = d_ee_conjectures.find( q[1] )!=d_ee_conjectures.end(); - if( !inEe ){ - //add to universal equality engine - Node nl = getUniversalRepresentative( eq[0], true ); - Node nr = getUniversalRepresentative( eq[1], true ); - if( areUniversalEqual( nl, nr ) ){ - isSubsume = true; - //set inactive (will be ignored by other modules) - d_quantEngine->getModel()->setQuantifierActive( q, false ); - }else{ - Node exp; - d_ee_conjectures[q[1]] = true; - d_uequalityEngine.assertEquality( nl.eqNode( nr ), true, exp ); - } - } - Trace("sg-conjecture") << "*** CONJECTURE : currently proven" << (isSubsume ? " and subsumed" : ""); - Trace("sg-conjecture") << " : " << q[1] << std::endl; - provenConj.push_back( q ); - } - if( !isSubsume ){ - Trace("thm-db-debug") << "Adding theorem to database " << eq[0] << " == " << eq[1] << std::endl; - d_thm_index.addTheorem( eq[0], eq[1] ); - }else{ - break; - } - }else{ - break; - } - } - } - } - //examine status of other conjectures - for( unsigned i=0; i sk; - //getTermDatabase()->getSkolemConstants( q, sk, true ); - Trace("sg-conjecture") << " CONJECTURE : "; - std::vector< Node > ce; - for( unsigned j=0; jd_skolem_constants[q].size(); j++ ){ - TNode k = getTermDatabase()->d_skolem_constants[q][j]; - TNode rk = getRepresentative( k ); - std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( rk ); - //check if it is a ground term - if( git==d_ground_eqc_map.end() ){ - Trace("sg-conjecture") << "ACTIVE : " << q; - if( Trace.isOn("sg-gen-eqc") ){ - Trace("sg-conjecture") << " { "; - for( unsigned k=0; kd_skolem_constants[q].size(); k++ ){ Trace("sg-conjecture") << getTermDatabase()->d_skolem_constants[q][k] << ( j==k ? "*" : "" ) << " "; } - Trace("sg-conjecture") << "}"; - } - Trace("sg-conjecture") << std::endl; - disproven = false; - break; - }else{ - ce.push_back( git->second ); - } - } - if( disproven ){ - Trace("sg-conjecture") << "disproven : " << q << " : "; - for( unsigned i=0; i " << ce[i] << " "; - } - Trace("sg-conjecture") << std::endl; - } - } - } - Trace("thm-db") << "Theorem database is : " << std::endl; - d_thm_index.debugPrint( "thm-db" ); - Trace("thm-db") << std::endl; - Trace("sg-proc") << "...done build theorem index" << std::endl; - - - //clear patterns - d_patterns.clear(); - d_pattern_var_id.clear(); - d_pattern_var_duplicate.clear(); - d_pattern_is_normal.clear(); - d_pattern_is_relevant.clear(); - d_pattern_fun_id.clear(); - d_pattern_fun_sum.clear(); - d_rel_patterns.clear(); - d_rel_pattern_var_sum.clear(); - d_rel_pattern_typ_index.clear(); - d_rel_pattern_subs_index.clear(); - - unsigned rel_term_count = 0; - std::map< TypeNode, unsigned > rt_var_max; - std::vector< TypeNode > rt_types; - std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs; - unsigned addedLemmas = 0; - for( unsigned depth=1; depth<=3; depth++ ){ - Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl; - Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl; - //set up environment - d_tge.d_var_id.clear(); - d_tge.d_var_limit.clear(); - d_tge.reset( depth, true, TypeNode::null() ); - while( d_tge.getNextTerm() ){ - //construct term - Node nn = d_tge.getTerm(); - if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){ - rel_term_count++; - Trace("sg-rel-term") << "*** Relevant term : "; - d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" ); - Trace("sg-rel-term") << std::endl; - - for( unsigned r=0; r<2; r++ ){ - Trace("sg-rel-term-debug") << "...from equivalence classes (" << r << ") : "; - int index = d_tge.d_ccand_eqc[r].size()-1; - for( unsigned j=0; j typ_to_subs_index; - std::vector< TNode > gsubs_vars; - for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){ - if( it->second>0 ){ - typ_to_subs_index[it->first] = sum; - sum += it->second; - for( unsigned i=0; isecond; i++ ){ - gsubs_vars.push_back( getFreeVar( it->first, i ) ); - } - } - } - d_rel_pattern_var_sum[nn] = sum; - //register the pattern - registerPattern( nn, tnn ); - Assert( d_pattern_is_normal[nn] ); - Trace("sg-gen-tg-debug") << "...done collect pattern information" << std::endl; - - //record information about types - Trace("sg-gen-tg-debug") << "Collect type information..." << std::endl; - PatternTypIndex * pti = &d_rel_pattern_typ_index; - for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){ - pti = &pti->d_children[it->first][it->second]; - //record maximum - if( rt_var_max.find( it->first )==rt_var_max.end() || it->second>rt_var_max[it->first] ){ - rt_var_max[it->first] = it->second; - } - } - if( std::find( rt_types.begin(), rt_types.end(), tnn )==rt_types.end() ){ - rt_types.push_back( tnn ); - } - pti->d_terms.push_back( nn ); - Trace("sg-gen-tg-debug") << "...done collect type information" << std::endl; - - Trace("sg-gen-tg-debug") << "Build substitutions for ground EQC..." << std::endl; - std::vector< TNode > gsubs_terms; - gsubs_terms.resize( gsubs_vars.size() ); - int index = d_tge.d_ccand_eqc[1].size()-1; - for( unsigned j=0; j > subs; - std::map< TNode, bool > rev_subs; - //only get ground terms - unsigned mode = 2; - d_tge.resetMatching( r, mode ); - while( d_tge.getNextMatch( r, subs, rev_subs ) ){ - //we will be building substitutions - bool firstTime = true; - for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator it = subs.begin(); it != subs.end(); ++it ){ - unsigned tindex = typ_to_subs_index[it->first]; - for( std::map< unsigned, TNode >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - if( !firstTime ){ - Trace("sg-rel-term-debug") << ", "; - }else{ - firstTime = false; - Trace("sg-rel-term-debug") << " "; - } - Trace("sg-rel-term-debug") << it->first << ":x" << it2->first << " -> " << it2->second; - Assert( tindex+it2->firstfirst] = it2->second; - } - } - Trace("sg-rel-term-debug") << std::endl; - d_rel_pattern_subs_index[nn].addSubstitution( r, gsubs_vars, gsubs_terms ); - } - } - Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl; - }else{ - Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl; - } - } - Trace("sg-proc") << "...done generate terms at depth " << depth << std::endl; - Trace("sg-stats") << "--------> Total LHS of depth " << depth << " : " << rel_term_count << std::endl; - //Trace("conjecture-count") << "Total LHS of depth " << depth << " : " << conj_lhs[depth].size() << std::endl; - - /* test... - for( unsigned i=0; i::iterator it = rt_var_max.begin(); it != rt_var_max.end(); ++it ){ - d_tge.d_var_id[ it->first ] = it->second; - d_tge.d_var_limit[ it->first ] = it->second; - } - std::random_shuffle( rt_types.begin(), rt_types.end() ); - std::map< TypeNode, std::vector< Node > > conj_rhs; - for( unsigned i=0; i >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){ - for( unsigned j=0; jsecond.size(); j++ ){ - for( unsigned k=0; kfirst][lhs_depth].size(); k++ ){ - processCandidateConjecture( conj_lhs[it->first][lhs_depth][k], it->second[j], lhs_depth, rdepth ); - } - } - } - flushWaitingConjectures( addedLemmas, lhs_depth, depth ); - } - } - } - if( (int)addedLemmas>=options::conjectureGenPerRound() ){ - break; - } - } - if( (int)addedLemmas>=options::conjectureGenPerRound() ){ - break; - } - } - Trace("sg-stats") << "Total conjectures considered : " << d_conj_count << std::endl; - if( Trace.isOn("thm-ee") ){ - Trace("thm-ee") << "Universal equality engine is : " << std::endl; - eq::EqClassesIterator ueqcs_i = eq::EqClassesIterator( &d_uequalityEngine ); - while( !ueqcs_i.isFinished() ){ - TNode r = (*ueqcs_i); - bool firstTime = true; - TNode rr = getUniversalRepresentative( r ); - Trace("thm-ee") << " " << rr; - Trace("thm-ee") << " : { "; - eq::EqClassIterator ueqc_i = eq::EqClassIterator( r, &d_uequalityEngine ); - while( !ueqc_i.isFinished() ){ - TNode n = (*ueqc_i); - if( rr!=n ){ - if( firstTime ){ - Trace("thm-ee") << std::endl; - firstTime = false; - } - Trace("thm-ee") << " " << n << std::endl; - } - ++ueqc_i; - } - if( !firstTime ){ Trace("thm-ee") << " "; } - Trace("thm-ee") << "}" << std::endl; - ++ueqcs_i; - } - Trace("thm-ee") << std::endl; - } - if( Trace.isOn("sg-engine") ){ - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Trace("sg-engine") << "Finished conjecture generator, time = " << (clSet2-clSet) << std::endl; - } - } - } -} - -unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) { - if( !d_waiting_conjectures_lhs.empty() ){ - Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl; - if( (int)addedLemmas indices; - for( unsigned i=0; i=optFilterScoreThreshold() ){ - //we have determined a relevant subgoal - Node lhs = d_waiting_conjectures_lhs[i]; - Node rhs = d_waiting_conjectures_rhs[i]; - if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){ - //skip - }else{ - Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl; - Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[i] << std::endl; - if( optStatsOnly() ){ - d_conj_count++; - }else{ - std::vector< Node > bvs; - for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[lhs].begin(); it != d_pattern_var_id[lhs].end(); ++it ){ - for( unsigned i=0; i<=it->second; i++ ){ - bvs.push_back( getFreeVar( it->first, i ) ); - } - } - Node rsg; - if( !bvs.empty() ){ - Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvs ); - rsg = NodeManager::currentNM()->mkNode( FORALL, bvl, lhs.eqNode( rhs ) ); - }else{ - rsg = lhs.eqNode( rhs ); - } - rsg = Rewriter::rewrite( rsg ); - d_conjectures.push_back( rsg ); - d_eq_conjectures[lhs].push_back( rhs ); - d_eq_conjectures[rhs].push_back( lhs ); - - Node lem = NodeManager::currentNM()->mkNode( OR, rsg.negate(), rsg ); - d_quantEngine->addLemma( lem, false ); - d_quantEngine->addRequirePhase( rsg, false ); - addedLemmas++; - if( (int)addedLemmas>=options::conjectureGenPerRound() ){ - break; - } - } - } - } - } - Trace("sg-proc") << "...have now added " << addedLemmas << " conjecture lemmas." << std::endl; - if( optStatsOnly() ){ - Trace("sg-stats") << "Generated " << (d_conj_count-prevCount) << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl; - } - } - d_waiting_conjectures_lhs.clear(); - d_waiting_conjectures_rhs.clear(); - d_waiting_conjectures_score.clear(); - d_waiting_conjectures.clear(); - } - return addedLemmas; -} - -void ConjectureGenerator::registerQuantifier( Node q ) { - -} - -void ConjectureGenerator::assertNode( Node n ) { - -} - -bool ConjectureGenerator::considerTermCanon( Node ln, bool genRelevant ){ - if( !ln.isNull() ){ - //do not consider if it is non-canonical, and either: - // (1) we are not generating relevant terms, or - // (2) its canonical form is a generalization. - TNode lnr = getUniversalRepresentative( ln, true ); - if( lnr==ln ){ - markReportedCanon( ln ); - }else if( !genRelevant || isGeneralization( lnr, ln ) ){ - Trace("sg-gen-consider-term") << "Do not consider term, " << ln << " is not canonical representation (which is " << lnr << ")." << std::endl; - return false; - } - } - Trace("sg-gen-tg-debug") << "Will consider term canon " << ln << std::endl; - Trace("sg-gen-consider-term-debug") << std::endl; - return true; -} - -unsigned ConjectureGenerator::collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs, - std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ){ - if( pat.hasOperator() ){ - funcs[pat.getOperator()]++; - if( !d_tge.isRelevantFunc( pat.getOperator() ) ){ - d_pattern_is_relevant[opat] = false; - } - unsigned sum = 1; - for( unsigned i=0; i1 ){ - //duplicate variable - d_pattern_var_duplicate[opat]++; - }else{ - //check for max/min - TypeNode tn = pat.getType(); - unsigned vn = d_free_var_num[pat]; - std::map< TypeNode, unsigned >::iterator it = mnvn.find( tn ); - if( it!=mnvn.end() ){ - if( vnsecond ){ - d_pattern_is_normal[opat] = false; - mnvn[tn] = vn; - }else if( vn>mxvn[tn] ){ - if( vn!=mxvn[tn]+1 ){ - d_pattern_is_normal[opat] = false; - } - mxvn[tn] = vn; - } - }else{ - //first variable of this type - mnvn[tn] = vn; - mxvn[tn] = vn; - } - } - }else{ - d_pattern_is_relevant[opat] = false; - } - return 1; - } -} - -void ConjectureGenerator::registerPattern( Node pat, TypeNode tpat ) { - if( std::find( d_patterns[tpat].begin(), d_patterns[tpat].end(), pat )==d_patterns[tpat].end() ){ - d_patterns[TypeNode::null()].push_back( pat ); - d_patterns[tpat].push_back( pat ); - - Assert( d_pattern_fun_id.find( pat )==d_pattern_fun_id.end() ); - Assert( d_pattern_var_id.find( pat )==d_pattern_var_id.end() ); - - //collect functions - std::map< TypeNode, unsigned > mnvn; - d_pattern_fun_sum[pat] = collectFunctions( pat, pat, d_pattern_fun_id[pat], mnvn, d_pattern_var_id[pat] ); - if( d_pattern_is_normal.find( pat )==d_pattern_is_normal.end() ){ - d_pattern_is_normal[pat] = true; - } - if( d_pattern_is_relevant.find( pat )==d_pattern_is_relevant.end() ){ - d_pattern_is_relevant[pat] = true; - } - } -} - -bool ConjectureGenerator::isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ) { - if( patg.getKind()==BOUND_VARIABLE ){ - std::map< TNode, TNode >::iterator it = subs.find( patg ); - if( it!=subs.end() ){ - return it->second==pat; - }else{ - subs[patg] = pat; - return true; - } - }else{ - Assert( patg.hasOperator() ); - if( !pat.hasOperator() || patg.getOperator()!=pat.getOperator() ){ - return false; - }else{ - Assert( patg.getNumChildren()==pat.getNumChildren() ); - for( unsigned i=0; i& fv ) { - if( n.getKind()==BOUND_VARIABLE ){ - if( std::find( fv.begin(), fv.end(), n )==fv.end() ){ - fv.push_back( n ); - return 0; - }else{ - return 1; - } - }else{ - int depth = 1; - for( unsigned i=0; i::iterator it = d_typ_pred.find( tn ); - if( it==d_typ_pred.end() ){ - TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->booleanType() ); - Node op = NodeManager::currentNM()->mkSkolem( "PE", op_tn, "was created by conjecture ground term enumerator." ); - d_typ_pred[tn] = op; - return op; - }else{ - return it->second; - } -} - -void ConjectureGenerator::getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ) { - if( n.getNumChildren()>0 ){ - std::vector< int > vec; - for( unsigned i=0; igetEnumerateTerm( n[index].getType(), vec[index]+1 ).isNull() ){ - vec[index]++; - vec_sum++; - vec.push_back( size_limit - vec_sum ); - }else{ - vec_sum -= vec[index]; - vec[index] = 0; - index++; - if( index==n.getNumChildren() ){ - success = false; - } - } - } - if( success ){ - if( vec.size()==n.getNumChildren() ){ - Node lc = getTermDatabase()->getEnumerateTerm( n[vec.size()-1].getType(), vec[vec.size()-1] ); - if( !lc.isNull() ){ - for( unsigned i=0; i children; - children.push_back( n.getOperator() ); - for( unsigned i=0; i<(vec.size()-1); i++ ){ - Node nn = getTermDatabase()->getEnumerateTerm( n[i].getType(), vec[i] ); - Assert( !nn.isNull() ); - Assert( nn.getType()==n[i].getType() ); - children.push_back( nn ); - } - children.push_back( lc ); - Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children ); - Trace("sg-gt-enum") << "Ground term enumerate : " << n << std::endl; - terms.push_back( n ); - } - vec.pop_back(); - index = 0; - } - }else{ - if( terms.size()>last_size ){ - last_size = terms.size(); - size_limit++; - for( unsigned i=0; i& terms ) { - std::vector< Node > uf_terms; - getEnumerateUfTerm( n, num, uf_terms ); - Node p = getPredicateForType( n.getType() ); - for( unsigned i=0; imkNode( APPLY_UF, p, uf_terms[i] ) ); - } -} - -void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ) { - int score = considerCandidateConjecture( lhs, rhs ); - if( score>0 ){ - Trace("sg-conjecture") << "* Candidate conjecture : " << lhs << " == " << rhs << std::endl; - Trace("sg-conjecture-debug") << " LHS, RHS generalization depth : " << lhs_depth << ", " << rhs_depth << std::endl; - Trace("sg-conjecture-debug") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl; - Trace("sg-conjecture-debug") << " #witnesses for "; - bool firstTime = true; - for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ - if( !firstTime ){ - Trace("sg-conjecture-debug") << ", "; - } - Trace("sg-conjecture-debug") << it->first << " : " << it->second.size(); - //if( it->second.size()==1 ){ - // Trace("sg-conjecture-debug") << " (" << it->second[0] << ")"; - //} - Trace("sg-conjecture-debug2") << " ("; - for( unsigned j=0; jsecond.size(); j++ ){ - if( j>0 ){ Trace("sg-conjecture-debug2") << " "; } - Trace("sg-conjecture-debug2") << d_ground_eqc_map[it->second[j]]; - } - Trace("sg-conjecture-debug2") << ")"; - firstTime = false; - } - Trace("sg-conjecture-debug") << std::endl; - Trace("sg-conjecture-debug") << " unknown = " << d_subs_unkCount << std::endl; - //Assert( getUniversalRepresentative( rhs )==rhs ); - //Assert( getUniversalRepresentative( lhs )==lhs ); - d_waiting_conjectures_lhs.push_back( lhs ); - d_waiting_conjectures_rhs.push_back( rhs ); - d_waiting_conjectures_score.push_back( score ); - d_waiting_conjectures[lhs].push_back( rhs ); - d_waiting_conjectures[rhs].push_back( lhs ); - } -} - -int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) { - Assert( lhs.getType()==rhs.getType() ); - - Trace("sg-cconj-debug") << "Consider candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl; - if( lhs==rhs ){ - Trace("sg-cconj-debug") << " -> trivial." << std::endl; - return -1; - }else{ - if( lhs.getKind()==APPLY_CONSTRUCTOR && rhs.getKind()==APPLY_CONSTRUCTOR ){ - Trace("sg-cconj-debug") << " -> irrelevant by syntactic analysis." << std::endl; - return -1; - } - //variables of LHS must subsume variables of RHS - for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[rhs].begin(); it != d_pattern_var_id[rhs].end(); ++it ){ - std::map< TypeNode, unsigned >::iterator itl = d_pattern_var_id[lhs].find( it->first ); - if( itl!=d_pattern_var_id[lhs].end() ){ - if( itl->secondsecond ){ - Trace("sg-cconj-debug") << " -> variables of sort " << it->first << " are not subsumed." << std::endl; - return -1; - }else{ - Trace("sg-cconj-debug2") << " variables of sort " << it->first << " are : " << itl->second << " vs " << it->second << std::endl; - } - }else{ - Trace("sg-cconj-debug") << " -> has no variables of sort " << it->first << "." << std::endl; - return -1; - } - } - - //currently active conjecture? - std::map< Node, std::vector< Node > >::iterator iteq = d_eq_conjectures.find( lhs ); - if( iteq!=d_eq_conjectures.end() ){ - if( std::find( iteq->second.begin(), iteq->second.end(), rhs )!=iteq->second.end() ){ - Trace("sg-cconj-debug") << " -> this conjecture is already active." << std::endl; - return -1; - } - } - //current a waiting conjecture? - std::map< Node, std::vector< Node > >::iterator itw = d_waiting_conjectures.find( lhs ); - if( itw!=d_waiting_conjectures.end() ){ - if( std::find( itw->second.begin(), itw->second.end(), rhs )!=itw->second.end() ){ - Trace("sg-cconj-debug") << " -> already are considering this conjecture." << std::endl; - return -1; - } - } - //check if canonical representation (should be, but for efficiency this is not guarenteed) - //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){ - // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl; - // return -1; - //} - - int score; - bool scoreSet = false; - - Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl; - //find witness for counterexample, if possible - if( options::conjectureFilterModel() ){ - Assert( d_rel_pattern_var_sum.find( lhs )!=d_rel_pattern_var_sum.end() ); - Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl; - std::map< TNode, TNode > subs; - d_subs_confirmCount = 0; - d_subs_confirmWitnessRange.clear(); - d_subs_confirmWitnessDomain.clear(); - d_subs_unkCount = 0; - if( !d_rel_pattern_subs_index[lhs].notifySubstitutions( this, subs, rhs, d_rel_pattern_var_sum[lhs] ) ){ - Trace("sg-cconj") << " -> found witness that falsifies the conjecture." << std::endl; - return -1; - } - //score is the minimum number of distinct substitutions for a variable - for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ - int num = (int)it->second.size(); - if( !scoreSet || num >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ - Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl; - } - }else{ - score = 1; - } - - Trace("sg-cconj") << " -> SUCCESS." << std::endl; - Trace("sg-cconj") << " score : " << score << std::endl; - - return score; - } -} - -bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ) { - if( Trace.isOn("sg-cconj-debug") ){ - Trace("sg-cconj-debug") << "Ground eqc for LHS : " << glhs << ", based on substituion: " << std::endl; - for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ - Assert( getRepresentative( it->second )==it->second ); - Trace("sg-cconj-debug") << " " << it->first << " -> " << it->second << std::endl; - } - } - Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl; - //get the representative of rhs with substitution subs - TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true ); - Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl; - if( !grhs.isNull() ){ - if( glhs!=grhs ){ - Trace("sg-cconj-debug") << "Ground eqc for RHS : " << grhs << std::endl; - //check based on ground terms - std::map< TNode, Node >::iterator itl = d_ground_eqc_map.find( glhs ); - if( itl!=d_ground_eqc_map.end() ){ - std::map< TNode, Node >::iterator itr = d_ground_eqc_map.find( grhs ); - if( itr!=d_ground_eqc_map.end() ){ - Trace("sg-cconj-debug") << "We have ground terms " << itl->second << " and " << itr->second << "." << std::endl; - if( itl->second.isConst() && itr->second.isConst() ){ - Trace("sg-cconj-debug") << "...disequal constants." << std::endl; - Trace("sg-cconj-witness") << " Witness of falsification : " << itl->second << " != " << itr->second << ", substutition is : " << std::endl; - for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ - Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl; - } - return false; - } - } - } - } - Trace("sg-cconj-debug") << "RHS is identical." << std::endl; - bool isGroundSubs = true; - for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ - std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( it->second ); - if( git==d_ground_eqc_map.end() ){ - isGroundSubs = false; - break; - } - } - if( isGroundSubs ){ - if( glhs==grhs ){ - Trace("sg-cconj-witness") << " Witnessed " << glhs << " == " << grhs << ", substutition is : " << std::endl; - for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ - Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl; - if( std::find( d_subs_confirmWitnessDomain[it->first].begin(), d_subs_confirmWitnessDomain[it->first].end(), it->second )==d_subs_confirmWitnessDomain[it->first].end() ){ - d_subs_confirmWitnessDomain[it->first].push_back( it->second ); - } - } - d_subs_confirmCount++; - if( std::find( d_subs_confirmWitnessRange.begin(), d_subs_confirmWitnessRange.end(), glhs )==d_subs_confirmWitnessRange.end() ){ - d_subs_confirmWitnessRange.push_back( glhs ); - } - }else{ - if( optFilterUnknown() ){ - Trace("sg-cconj-debug") << "...ground substitution giving terms that are neither equal nor disequal." << std::endl; - return false; - } - } - } - }else{ - Trace("sg-cconj-debug") << "(could not ground eqc for RHS)." << std::endl; - } - return true; -} - - - - - - -void TermGenerator::reset( TermGenEnv * s, TypeNode tn ) { - Assert( d_children.empty() ); - d_typ = tn; - d_status = 0; - d_status_num = 0; - d_children.clear(); - Trace("sg-gen-tg-debug2") << "...add to context " << this << std::endl; - d_id = s->d_tg_id; - s->changeContext( true ); -} - -bool TermGenerator::getNextTerm( TermGenEnv * s, unsigned depth ) { - if( Trace.isOn("sg-gen-tg-debug2") ){ - Trace("sg-gen-tg-debug2") << this << " getNextTerm depth " << depth << " : status = " << d_status << ", num = " << d_status_num; - if( d_status==5 ){ - TNode f = s->getTgFunc( d_typ, d_status_num ); - Trace("sg-gen-tg-debug2") << ", f = " << f; - Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size(); - Trace("sg-gen-tg-debug2") << ", childNum = " << d_status_child_num; - Trace("sg-gen-tg-debug2") << ", #children = " << d_children.size(); - } - Trace("sg-gen-tg-debug2") << std::endl; - } - - if( d_status==0 ){ - d_status++; - if( !d_typ.isNull() ){ - if( s->allowVar( d_typ ) ){ - //allocate variable - d_status_num = s->d_var_id[d_typ]; - s->addVar( d_typ ); - Trace("sg-gen-tg-debug2") << this << " ...return unique var #" << d_status_num << std::endl; - return s->considerCurrentTerm() ? true : getNextTerm( s, depth ); - }else{ - //check allocating new variable - d_status++; - d_status_num = -1; - if( s->d_gen_relevant_terms ){ - s->d_tg_gdepth++; - } - return getNextTerm( s, depth ); - } - }else{ - d_status = 4; - d_status_num = -1; - return getNextTerm( s, depth ); - } - }else if( d_status==2 ){ - //cleanup previous information - //if( d_status_num>=0 ){ - // s->d_var_eq_tg[d_status_num].pop_back(); - //} - //check if there is another variable - if( (d_status_num+1)<(int)s->getNumTgVars( d_typ ) ){ - d_status_num++; - //we have equated two variables - //s->d_var_eq_tg[d_status_num].push_back( d_id ); - Trace("sg-gen-tg-debug2") << this << "...consider other var #" << d_status_num << std::endl; - return s->considerCurrentTerm() ? true : getNextTerm( s, depth ); - }else{ - if( s->d_gen_relevant_terms ){ - s->d_tg_gdepth--; - } - d_status++; - return getNextTerm( s, depth ); - } - }else if( d_status==4 ){ - d_status++; - if( depth>0 && (d_status_num+1)<(int)s->getNumTgFuncs( d_typ ) ){ - d_status_num++; - d_status_child_num = 0; - Trace("sg-gen-tg-debug2") << this << "...consider function " << s->getTgFunc( d_typ, d_status_num ) << std::endl; - s->d_tg_gdepth++; - if( !s->considerCurrentTerm() ){ - s->d_tg_gdepth--; - //don't consider this function - d_status--; - }else{ - //we have decided on a function application - } - return getNextTerm( s, depth ); - }else{ - //do not choose function applications at depth 0 - d_status++; - return getNextTerm( s, depth ); - } - }else if( d_status==5 ){ - //iterating over arguments - TNode f = s->getTgFunc( d_typ, d_status_num ); - if( d_status_child_num<0 ){ - //no more arguments - s->d_tg_gdepth--; - d_status--; - return getNextTerm( s, depth ); - }else if( d_status_child_num==(int)s->d_func_args[f].size() ){ - d_status_child_num--; - return s->considerCurrentTermCanon( d_id ) ? true : getNextTerm( s, depth ); - //return true; - }else{ - Assert( d_status_child_num<(int)s->d_func_args[f].size() ); - if( d_status_child_num==(int)d_children.size() ){ - d_children.push_back( s->d_tg_id ); - Assert( s->d_tg_alloc.find( s->d_tg_id )==s->d_tg_alloc.end() ); - s->d_tg_alloc[d_children[d_status_child_num]].reset( s, s->d_func_args[f][d_status_child_num] ); - return getNextTerm( s, depth ); - }else{ - Assert( d_status_child_num+1==(int)d_children.size() ); - if( s->d_tg_alloc[d_children[d_status_child_num]].getNextTerm( s, depth-1 ) ){ - d_status_child_num++; - return getNextTerm( s, depth ); - }else{ - d_children.pop_back(); - d_status_child_num--; - return getNextTerm( s, depth ); - } - } - } - }else if( d_status==1 || d_status==3 ){ - if( d_status==1 ){ - s->removeVar( d_typ ); - Assert( d_status_num==(int)s->d_var_id[d_typ] ); - //check if there is only one feasible equivalence class. if so, don't make pattern any more specific. - //unsigned i = s->d_ccand_eqc[0].size()-1; - //if( s->d_ccand_eqc[0][i].size()==1 && s->d_ccand_eqc[1][i].empty() ){ - // d_status = 6; - // return getNextTerm( s, depth ); - //} - s->d_tg_gdepth++; - } - d_status++; - d_status_num = -1; - return getNextTerm( s, depth ); - }else{ - //clean up - Assert( d_children.empty() ); - Trace("sg-gen-tg-debug2") << "...remove from context " << this << std::endl; - s->changeContext( false ); - Assert( d_id==s->d_tg_id ); - return false; - } -} - -void TermGenerator::resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ) { - d_match_status = 0; - d_match_status_child_num = 0; - d_match_children.clear(); - d_match_children_end.clear(); - d_match_mode = mode; - //if this term generalizes, it must generalize a non-ground term - //if( (d_match_mode & ( 1 << 2 ))!=0 && s->isGroundEqc( eqc ) && d_status==5 ){ - // d_match_status = -1; - //} -} - -bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) { - if( d_match_status<0 ){ - return false; - } - if( Trace.isOn("sg-gen-tg-match") ){ - Trace("sg-gen-tg-match") << "Matching "; - debugPrint( s, "sg-gen-tg-match", "sg-gen-tg-match" ); - Trace("sg-gen-tg-match") << " with eqc e" << s->d_cg->d_em[eqc] << "..." << std::endl; - Trace("sg-gen-tg-match") << " mstatus = " << d_match_status; - if( d_status==5 ){ - TNode f = s->getTgFunc( d_typ, d_status_num ); - Trace("sg-gen-tg-debug2") << ", f = " << f; - Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size(); - Trace("sg-gen-tg-debug2") << ", mchildNum = " << d_match_status_child_num; - Trace("sg-gen-tg-debug2") << ", #mchildren = " << d_match_children.size(); - } - Trace("sg-gen-tg-debug2") << ", current substitution : {"; - for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator itt = subs.begin(); itt != subs.end(); ++itt ){ - for( std::map< unsigned, TNode >::iterator it = itt->second.begin(); it != itt->second.end(); ++it ){ - Trace("sg-gen-tg-debug2") << " " << it->first << " -> e" << s->d_cg->d_em[it->second]; - } - } - Trace("sg-gen-tg-debug2") << " } " << std::endl; - } - if( d_status==1 ){ - //a variable - if( d_match_status==0 ){ - d_match_status++; - if( (d_match_mode & ( 1 << 1 ))!=0 ){ - //only ground terms - if( !s->isGroundEqc( eqc ) ){ - return false; - } - }else if( (d_match_mode & ( 1 << 2 ))!=0 ){ - //only non-ground terms - //if( s->isGroundEqc( eqc ) ){ - // return false; - //} - } - //store the match : restricted if match_mode.0 = 1 - if( (d_match_mode & ( 1 << 0 ))!=0 ){ - std::map< TNode, bool >::iterator it = rev_subs.find( eqc ); - if( it==rev_subs.end() ){ - rev_subs[eqc] = true; - }else{ - return false; - } - } - Assert( subs[d_typ].find( d_status_num )==subs[d_typ].end() ); - subs[d_typ][d_status_num] = eqc; - return true; - }else{ - //clean up - subs[d_typ].erase( d_status_num ); - if( (d_match_mode & ( 1 << 0 ))!=0 ){ - rev_subs.erase( eqc ); - } - return false; - } - }else if( d_status==2 ){ - if( d_match_status==0 ){ - d_match_status++; - Assert( d_status_num<(int)s->getNumTgVars( d_typ ) ); - std::map< unsigned, TNode >::iterator it = subs[d_typ].find( d_status_num ); - Assert( it!=subs[d_typ].end() ); - return it->second==eqc; - }else{ - return false; - } - }else if( d_status==5 ){ - //Assert( d_match_children.size()<=d_children.size() ); - //enumerating over f-applications in eqc - if( d_match_status_child_num<0 ){ - return false; - }else if( d_match_status==0 ){ - //set up next binding - if( d_match_status_child_num==(int)d_match_children.size() ){ - if( d_match_status_child_num==0 ){ - //initial binding - TNode f = s->getTgFunc( d_typ, d_status_num ); - std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc ); - if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){ - d_match_children.push_back( it->second.d_data.begin() ); - d_match_children_end.push_back( it->second.d_data.end() ); - }else{ - d_match_status++; - d_match_status_child_num--; - return getNextMatch( s, eqc, subs, rev_subs ); - } - }else{ - d_match_children.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.begin() ); - d_match_children_end.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.end() ); - } - } - d_match_status++; - Assert( d_match_status_child_num+1==(int)d_match_children.size() ); - if( d_match_children[d_match_status_child_num]==d_match_children_end[d_match_status_child_num] ){ - //no more arguments to bind - d_match_children.pop_back(); - d_match_children_end.pop_back(); - d_match_status_child_num--; - return getNextMatch( s, eqc, subs, rev_subs ); - }else{ - if( d_match_status_child_num==(int)d_children.size() ){ - //successfully matched all children - d_match_children.pop_back(); - d_match_children_end.pop_back(); - d_match_status_child_num--; - return true;//return d_match_children[d_match_status]!=d_match_children_end[d_match_status]; - }else{ - //do next binding - s->d_tg_alloc[d_children[d_match_status_child_num]].resetMatching( s, d_match_children[d_match_status_child_num]->first, d_match_mode ); - return getNextMatch( s, eqc, subs, rev_subs ); - } - } - }else{ - Assert( d_match_status==1 ); - Assert( d_match_status_child_num+1==(int)d_match_children.size() ); - Assert( d_match_children[d_match_status_child_num]!=d_match_children_end[d_match_status_child_num] ); - d_match_status--; - if( s->d_tg_alloc[d_children[d_match_status_child_num]].getNextMatch( s, d_match_children[d_match_status_child_num]->first, subs, rev_subs ) ){ - d_match_status_child_num++; - return getNextMatch( s, eqc, subs, rev_subs ); - }else{ - //iterate - d_match_children[d_match_status_child_num]++; - return getNextMatch( s, eqc, subs, rev_subs ); - } - } - } - Assert( false ); - return false; -} - -unsigned TermGenerator::getDepth( TermGenEnv * s ) { - if( d_status==5 ){ - unsigned maxd = 0; - for( unsigned i=0; id_tg_alloc[d_children[i]].getDepth( s ); - if( d>maxd ){ - maxd = d; - } - } - return 1+maxd; - }else{ - return 0; - } -} - -unsigned TermGenerator::calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ) { - if( d_status==5 ){ - unsigned sum = 1; - for( unsigned i=0; id_tg_alloc[d_children[i]].calculateGeneralizationDepth( s, fvs ); - } - return sum; - }else{ - Assert( d_status==2 || d_status==1 ); - std::map< TypeNode, std::vector< int > >::iterator it = fvs.find( d_typ ); - if( it!=fvs.end() ){ - if( std::find( it->second.begin(), it->second.end(), d_status_num )!=it->second.end() ){ - return 1; - } - } - fvs[d_typ].push_back( d_status_num ); - return 0; - } -} - -unsigned TermGenerator::getGeneralizationDepth( TermGenEnv * s ) { - //if( s->d_gen_relevant_terms ){ - // return s->d_tg_gdepth; - //}else{ - std::map< TypeNode, std::vector< int > > fvs; - return calculateGeneralizationDepth( s, fvs ); - //} -} - -Node TermGenerator::getTerm( TermGenEnv * s ) { - if( d_status==1 || d_status==2 ){ - Assert( !d_typ.isNull() ); - return s->getFreeVar( d_typ, d_status_num ); - }else if( d_status==5 ){ - Node f = s->getTgFunc( d_typ, d_status_num ); - if( d_children.size()==s->d_func_args[f].size() ){ - std::vector< Node > children; - if( s->d_tg_func_param[f] ){ - children.push_back( f ); - } - for( unsigned i=0; id_tg_alloc[d_children[i]].getTerm( s ); - if( nc.isNull() ){ - return Node::null(); - }else{ - //Assert( nc.getType()==s->d_func_args[f][i] ); - children.push_back( nc ); - } - } - return NodeManager::currentNM()->mkNode( s->d_func_kind[f], children ); - } - }else{ - Assert( false ); - } - return Node::null(); -} - -void TermGenerator::debugPrint( TermGenEnv * s, const char * c, const char * cd ) { - Trace(cd) << "[*" << d_id << "," << d_status << "]:"; - if( d_status==1 || d_status==2 ){ - Trace(c) << s->getFreeVar( d_typ, d_status_num ); - }else if( d_status==5 ){ - TNode f = s->getTgFunc( d_typ, d_status_num ); - Trace(c) << "(" << f; - for( unsigned i=0; id_tg_alloc[d_children[i]].debugPrint( s, c, cd ); - } - if( d_children.size()d_func_args[f].size() ){ - Trace(c) << " ..."; - } - Trace(c) << ")"; - }else{ - Trace(c) << "???"; - } -} - -void TermGenEnv::collectSignatureInformation() { - d_typ_tg_funcs.clear(); - d_funcs.clear(); - d_func_kind.clear(); - d_func_args.clear(); - TypeNode tnull; - for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){ - if( !getTermDatabase()->d_op_map[it->first].empty() ){ - Node nn = getTermDatabase()->d_op_map[it->first][0]; - if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){ - bool do_enum = true; - //check if we have enumerated ground terms - if( nn.getKind()==APPLY_UF ){ - if( !d_cg->hasEnumeratedUf( nn ) ){ - do_enum = false; - } - } - if( do_enum ){ - d_funcs.push_back( it->first ); - for( unsigned i=0; ifirst].push_back( nn[i].getType() ); - } - d_func_kind[it->first] = nn.getKind(); - d_typ_tg_funcs[tnull].push_back( it->first ); - d_typ_tg_funcs[nn.getType()].push_back( it->first ); - d_tg_func_param[it->first] = ( nn.getMetaKind() == kind::metakind::PARAMETERIZED ); - Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl; - getTermDatabase()->computeUfEqcTerms( it->first ); - } - } - } - } - //shuffle functions - for( std::map< TypeNode, std::vector< TNode > >::iterator it = d_typ_tg_funcs.begin(); it != d_typ_tg_funcs.end(); ++it ){ - std::random_shuffle( it->second.begin(), it->second.end() ); - if( it->first.isNull() ){ - Trace("sg-gen-tg-debug") << "In this order : "; - for( unsigned i=0; isecond.size(); i++ ){ - Trace("sg-gen-tg-debug") << it->second[i] << " "; - } - Trace("sg-gen-tg-debug") << std::endl; - } - } -} - -void TermGenEnv::reset( unsigned depth, bool genRelevant, TypeNode tn ) { - Assert( d_tg_alloc.empty() ); - d_tg_alloc.clear(); - - if( genRelevant ){ - for( unsigned i=0; i<2; i++ ){ - d_ccand_eqc[i].clear(); - d_ccand_eqc[i].push_back( d_relevant_eqc[i] ); - } - } - - d_tg_id = 0; - d_tg_gdepth = 0; - d_tg_gdepth_limit = depth; - d_gen_relevant_terms = genRelevant; - d_tg_alloc[0].reset( this, tn ); -} - -bool TermGenEnv::getNextTerm() { - if( d_tg_alloc[0].getNextTerm( this, d_tg_gdepth_limit ) ){ - Assert( (int)d_tg_alloc[0].getGeneralizationDepth( this )<=d_tg_gdepth_limit ); - if( (int)d_tg_alloc[0].getGeneralizationDepth( this )!=d_tg_gdepth_limit ){ - return getNextTerm(); - }else{ - return true; - } - }else{ - return false; - } -} - -//reset matching -void TermGenEnv::resetMatching( TNode eqc, unsigned mode ) { - d_tg_alloc[0].resetMatching( this, eqc, mode ); -} - -//get next match -bool TermGenEnv::getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) { - return d_tg_alloc[0].getNextMatch( this, eqc, subs, rev_subs ); -} - -//get term -Node TermGenEnv::getTerm() { - return d_tg_alloc[0].getTerm( this ); -} - -void TermGenEnv::debugPrint( const char * c, const char * cd ) { - d_tg_alloc[0].debugPrint( this, c, cd ); -} - -unsigned TermGenEnv::getNumTgVars( TypeNode tn ) { - return d_var_id[tn]; -} - -bool TermGenEnv::allowVar( TypeNode tn ) { - std::map< TypeNode, unsigned >::iterator it = d_var_limit.find( tn ); - if( it==d_var_limit.end() ){ - return true; - }else{ - return d_var_id[tn]second; - } -} - -void TermGenEnv::addVar( TypeNode tn ) { - d_var_id[tn]++; -} - -void TermGenEnv::removeVar( TypeNode tn ) { - d_var_id[tn]--; - //d_var_eq_tg.pop_back(); - //d_var_tg.pop_back(); -} - -unsigned TermGenEnv::getNumTgFuncs( TypeNode tn ) { - return d_typ_tg_funcs[tn].size(); -} - -TNode TermGenEnv::getTgFunc( TypeNode tn, unsigned i ) { - return d_typ_tg_funcs[tn][i]; -} - -Node TermGenEnv::getFreeVar( TypeNode tn, unsigned i ) { - return d_cg->getFreeVar( tn, i ); -} - -bool TermGenEnv::considerCurrentTerm() { - Assert( !d_tg_alloc.empty() ); - - //if generalization depth is too large, don't consider it - unsigned i = d_tg_alloc.size(); - Trace("sg-gen-tg-debug") << "Consider term "; - d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" ); - Trace("sg-gen-tg-debug") << "? curr term size = " << d_tg_alloc.size() << ", last status = " << d_tg_alloc[i-1].d_status; - Trace("sg-gen-tg-debug") << std::endl; - - if( d_tg_gdepth_limit>=0 && d_tg_alloc[0].getGeneralizationDepth( this )>(unsigned)d_tg_gdepth_limit ){ - Trace("sg-gen-consider-term") << "-> generalization depth of "; - d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-tg-debug" ); - Trace("sg-gen-consider-term") << " is too high " << d_tg_gdepth << " " << d_tg_alloc[0].getGeneralizationDepth( this ) << ", do not consider." << std::endl; - return false; - } - - //----optimizations - /* - if( d_tg_alloc[i-1].d_status==1 ){ - }else if( d_tg_alloc[i-1].d_status==2 ){ - }else if( d_tg_alloc[i-1].d_status==5 ){ - }else{ - Trace("sg-gen-tg-debug") << "Bad tg: " << &d_tg_alloc[i-1] << std::endl; - Assert( false ); - } - */ - //if equated two variables, first check if context-independent TODO - //----end optimizations - - - //check based on which candidate equivalence classes match - if( d_gen_relevant_terms ){ - Trace("sg-gen-tg-debug") << "Filter based on relevant ground EQC"; - Trace("sg-gen-tg-debug") << ", #eqc to try = " << d_ccand_eqc[0][i-1].size() << "/" << d_ccand_eqc[1][i-1].size() << std::endl; - - Assert( d_ccand_eqc[0].size()>=2 ); - Assert( d_ccand_eqc[0].size()==d_ccand_eqc[1].size() ); - Assert( d_ccand_eqc[0].size()==d_tg_id+1 ); - Assert( d_tg_id==d_tg_alloc.size() ); - for( unsigned r=0; r<2; r++ ){ - d_ccand_eqc[r][i].clear(); - } - - //re-check feasibility of EQC - for( unsigned r=0; r<2; r++ ){ - for( unsigned j=0; j > subs; - std::map< TNode, bool > rev_subs; - unsigned mode; - if( r==0 ){ - mode = d_cg->optReqDistinctVarPatterns() ? ( 1 << 0 ) : 0; - mode = mode | (1 << 2 ); - }else{ - mode = 1 << 1; - } - d_tg_alloc[0].resetMatching( this, d_ccand_eqc[r][i-1][j], mode ); - if( d_tg_alloc[0].getNextMatch( this, d_ccand_eqc[r][i-1][j], subs, rev_subs ) ){ - d_ccand_eqc[r][i].push_back( d_ccand_eqc[r][i-1][j] ); - } - } - } - for( unsigned r=0; r<2; r++ ){ - Trace("sg-gen-tg-debug") << "Current eqc of type " << r << " : "; - for( unsigned j=0; jd_em[d_ccand_eqc[r][i][j]] << " "; - } - Trace("sg-gen-tg-debug") << std::endl; - } - if( options::conjectureFilterActiveTerms() && d_ccand_eqc[0][i].empty() ){ - Trace("sg-gen-consider-term") << "Do not consider term of form "; - d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" ); - Trace("sg-gen-consider-term") << " since no relevant EQC matches it." << std::endl; - return false; - } - if( options::conjectureFilterModel() && d_ccand_eqc[1][i].empty() ){ - Trace("sg-gen-consider-term") << "Do not consider term of form "; - d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" ); - Trace("sg-gen-consider-term") << " since no ground EQC matches it." << std::endl; - return false; - } - } - Trace("sg-gen-tg-debug") << "Will consider term "; - d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" ); - Trace("sg-gen-tg-debug") << std::endl; - Trace("sg-gen-consider-term-debug") << std::endl; - return true; -} - -void TermGenEnv::changeContext( bool add ) { - if( add ){ - for( unsigned r=0; r<2; r++ ){ - d_ccand_eqc[r].push_back( std::vector< TNode >() ); - } - d_tg_id++; - }else{ - for( unsigned r=0; r<2; r++ ){ - d_ccand_eqc[r].pop_back(); - } - d_tg_id--; - Assert( d_tg_alloc.find( d_tg_id )!=d_tg_alloc.end() ); - d_tg_alloc.erase( d_tg_id ); - } -} - -bool TermGenEnv::considerCurrentTermCanon( unsigned tg_id ){ - Assert( tg_idconsiderTermCanon( ln, d_gen_relevant_terms ); - } - return true; -} - -bool TermGenEnv::isRelevantFunc( Node f ) { - return std::find( d_funcs.begin(), d_funcs.end(), f )!=d_funcs.end(); -} -TermDb * TermGenEnv::getTermDatabase() { - return d_cg->getTermDatabase(); -} -Node TermGenEnv::getGroundEqc( TNode r ) { - return d_cg->getGroundEqc( r ); -} -bool TermGenEnv::isGroundEqc( TNode r ){ - return d_cg->isGroundEqc( r ); -} -bool TermGenEnv::isGroundTerm( TNode n ){ - return d_cg->isGroundTerm( n ); -} - - -void SubstitutionIndex::addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i ) { - if( i==vars.size() ){ - d_var = eqc; - }else{ - Assert( d_var.isNull() || d_var==vars[i] ); - d_var = vars[i]; - d_children[terms[i]].addSubstitution( eqc, vars, terms, i+1 ); - } -} - -bool SubstitutionIndex::notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i ) { - if( i==numVars ){ - Assert( d_children.empty() ); - return s->notifySubstitution( d_var, subs, rhs ); - }else{ - Assert( i==0 || !d_children.empty() ); - for( std::map< TNode, SubstitutionIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ - Trace("sg-cconj-debug2") << "Try " << d_var << " -> " << it->first << " (" << i << "/" << numVars << ")" << std::endl; - subs[d_var] = it->first; - if( !it->second.notifySubstitutions( s, subs, rhs, numVars, i+1 ) ){ - return false; - } - } - return true; - } -} - - -void TheoremIndex::addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){ - if( lhs_v.empty() ){ - if( std::find( d_terms.begin(), d_terms.end(), rhs )==d_terms.end() ){ - d_terms.push_back( rhs ); - } - }else{ - unsigned index = lhs_v.size()-1; - if( lhs_arg[index]==lhs_v[index].getNumChildren() ){ - lhs_v.pop_back(); - lhs_arg.pop_back(); - addTheorem( lhs_v, lhs_arg, rhs ); - }else{ - lhs_arg[index]++; - addTheoremNode( lhs_v[index][lhs_arg[index]-1], lhs_v, lhs_arg, rhs ); - } - } -} - -void TheoremIndex::addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){ - Trace("thm-db-debug") << "Adding conjecture for subterm " << curr << "..." << std::endl; - if( curr.hasOperator() ){ - lhs_v.push_back( curr ); - lhs_arg.push_back( 0 ); - d_children[curr.getOperator()].addTheorem( lhs_v, lhs_arg, rhs ); - }else{ - Assert( curr.getKind()==kind::BOUND_VARIABLE ); - TypeNode tn = curr.getType(); - Assert( d_var[tn].isNull() || d_var[tn]==curr ); - d_var[tn] = curr; - d_children[curr].addTheorem( lhs_v, lhs_arg, rhs ); - } -} - -void TheoremIndex::getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg, - std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, - std::vector< Node >& terms ) { - Trace("thm-db-debug") << "Get equivalent terms " << n_v.size() << " " << n_arg.size() << std::endl; - if( n_v.empty() ){ - Trace("thm-db-debug") << "Number of terms : " << d_terms.size() << std::endl; - //apply substutitions to RHS's - for( unsigned i=0; i& n_v, std::vector< unsigned >& n_arg, - std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, - std::vector< Node >& terms ) { - Trace("thm-db-debug") << "Get equivalent based on subterm " << curr << "..." << std::endl; - if( curr.hasOperator() ){ - Trace("thm-db-debug") << "Check based on operator..." << std::endl; - std::map< TNode, TheoremIndex >::iterator it = d_children.find( curr.getOperator() ); - if( it!=d_children.end() ){ - n_v.push_back( curr ); - n_arg.push_back( 0 ); - it->second.getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms ); - } - Trace("thm-db-debug") << "...done check based on operator" << std::endl; - } - TypeNode tn = curr.getType(); - std::map< TypeNode, TNode >::iterator itt = d_var.find( tn ); - if( itt!=d_var.end() ){ - Trace("thm-db-debug") << "Check for substitution with " << itt->second << "..." << std::endl; - Assert( curr.getType()==itt->second.getType() ); - //add to substitution if possible - bool success = false; - std::map< TNode, TNode >::iterator it = smap.find( itt->second ); - if( it==smap.end() ){ - smap[itt->second] = curr; - vars.push_back( itt->second ); - subs.push_back( curr ); - success = true; - }else if( it->second==curr ){ - success = true; - }else{ - //also check modulo equality (in universal equality engine) - } - Trace("thm-db-debug") << "...check for substitution with " << itt->second << ", success = " << success << "." << std::endl; - if( success ){ - d_children[itt->second].getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms ); - } - } -} - -void TheoremIndex::debugPrint( const char * c, unsigned ind ) { - for( std::map< TNode, TheoremIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ - for( unsigned i=0; ifirst << std::endl; - it->second.debugPrint( c, ind+1 ); - } - if( !d_terms.empty() ){ - for( unsigned i=0; i d_scores; + bool operator() (unsigned i, unsigned j) { return d_scores[i]>d_scores[j]; } +}; + + +void OpArgIndex::addTerm( ConjectureGenerator * s, TNode n, unsigned index ){ + if( index==n.getNumChildren() ){ + Assert( n.hasOperator() ); + if( std::find( d_ops.begin(), d_ops.end(), n.getOperator() )==d_ops.end() ){ + d_ops.push_back( n.getOperator() ); + d_op_terms.push_back( n ); + } + }else{ + d_child[s->getTermDatabase()->d_arg_reps[n][index]].addTerm( s, n, index+1 ); + } +} + +Node OpArgIndex::getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ) { + if( d_ops.empty() ){ + for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){ + std::map< TNode, Node >::iterator itf = s->d_ground_eqc_map.find( it->first ); + if( itf!=s->d_ground_eqc_map.end() ){ + args.push_back( itf->second ); + Node n = it->second.getGroundTerm( s, args ); + args.pop_back(); + if( !n.isNull() ){ + return n; + } + } + } + return Node::null(); + }else{ + std::vector< TNode > args2; + args2.push_back( d_ops[0] ); + args2.insert( args2.end(), args.begin(), args.end() ); + return NodeManager::currentNM()->mkNode( d_op_terms[0].getKind(), args2 ); + } +} + +void OpArgIndex::getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ) { + terms.insert( terms.end(), d_op_terms.begin(), d_op_terms.end() ); + for( std::map< TNode, OpArgIndex >::iterator it = d_child.begin(); it != d_child.end(); ++it ){ + if( s->isGroundEqc( it->first ) ){ + it->second.getGroundTerms( s, terms ); + } + } +} + + + +ConjectureGenerator::ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ), +d_notify( *this ), +d_uequalityEngine(d_notify, c, "ConjectureGenerator::ee", false), +d_ee_conjectures( c ){ + d_fullEffortCount = 0; + d_uequalityEngine.addFunctionKind( kind::APPLY_UF ); + d_uequalityEngine.addFunctionKind( kind::APPLY_CONSTRUCTOR ); + +} + +void ConjectureGenerator::eqNotifyNewClass( TNode t ){ + Trace("thm-ee-debug") << "UEE : new equivalence class " << t << std::endl; + d_upendingAdds.push_back( t ); +} + +void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) { + //get maintained representatives + TNode rt1 = t1; + TNode rt2 = t2; + std::map< Node, EqcInfo* >::iterator it1 = d_eqc_info.find( t1 ); + if( it1!=d_eqc_info.end() && !it1->second->d_rep.get().isNull() ){ + rt1 = it1->second->d_rep.get(); + } + std::map< Node, EqcInfo* >::iterator it2 = d_eqc_info.find( t2 ); + if( it2!=d_eqc_info.end() && !it2->second->d_rep.get().isNull() ){ + rt2 = it2->second->d_rep.get(); + } + Trace("thm-ee-debug") << "UEE : equality holds : " << t1 << " == " << t2 << std::endl; + Trace("thm-ee-debug") << " ureps : " << rt1 << " == " << rt2 << std::endl; + Trace("thm-ee-debug") << " relevant : " << d_pattern_is_relevant[rt1] << " " << d_pattern_is_relevant[rt2] << std::endl; + Trace("thm-ee-debug") << " normal : " << d_pattern_is_normal[rt1] << " " << d_pattern_is_normal[rt2] << std::endl; + Trace("thm-ee-debug") << " size : " << d_pattern_fun_sum[rt1] << " " << d_pattern_fun_sum[rt2] << std::endl; + + if( isUniversalLessThan( rt2, rt1 ) ){ + EqcInfo * ei; + if( it1==d_eqc_info.end() ){ + ei = getOrMakeEqcInfo( t1, true ); + }else{ + ei = it1->second; + } + ei->d_rep = t2; + } +} + +void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) { + +} + +void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { + Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl; + +} + + +ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){ + +} + +ConjectureGenerator::EqcInfo* ConjectureGenerator::getOrMakeEqcInfo( TNode n, bool doMake ) { + //Assert( getUniversalRepresentative( n )==n ); + std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n ); + if( eqc_i!=d_eqc_info.end() ){ + return eqc_i->second; + }else if( doMake ){ + EqcInfo* ei = new EqcInfo( d_quantEngine->getSatContext() ); + d_eqc_info[n] = ei; + return ei; + }else{ + return NULL; + } +} + +void ConjectureGenerator::setUniversalRelevant( TNode n ) { + //add pattern information + registerPattern( n, n.getType() ); + d_urelevant_terms[n] = true; + for( unsigned i=0; i pending; + pending.insert( pending.end(), d_upendingAdds.begin(), d_upendingAdds.end() ); + d_upendingAdds.clear(); + for( unsigned i=0; i eq_terms; + //if occurs modulo equality at ground level, it is equivalent to representative of ground equality engine + TNode gt = getTermDatabase()->evaluateTerm( t ); + if( !gt.isNull() && gt!=t ){ + eq_terms.push_back( gt ); + } + //get all equivalent terms based on theorem database + d_thm_index.getEquivalentTerms( t, eq_terms ); + if( !eq_terms.empty() ){ + Trace("thm-ee-add") << "UEE : Based on ground EE/theorem DB, it is equivalent to " << eq_terms.size() << " terms : " << std::endl; + //add equivalent terms as equalities to universal engine + for( unsigned i=0; i=d_pattern_fun_sum[eq_terms[i]] ) ){ + setUniversalRelevant( eq_terms[i] ); + assertEq = true; + } + } + if( assertEq ){ + Node exp; + d_uequalityEngine.assertEquality( t.eqNode( eq_terms[i] ), true, exp ); + }else{ + Trace("thm-ee-no-add") << "Do not add : " << t << " == " << eq_terms[i] << std::endl; + } + } + }else{ + Trace("thm-ee-add") << "UEE : No equivalent terms." << std::endl; + } + } + } + } + } + + if( d_uequalityEngine.hasTerm( n ) ){ + Node r = d_uequalityEngine.getRepresentative( n ); + EqcInfo * ei = getOrMakeEqcInfo( r ); + if( ei && !ei->d_rep.get().isNull() ){ + return ei->d_rep.get(); + }else{ + return r; + } + }else{ + return n; + } +} + +Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) { + Assert( !tn.isNull() ); + while( d_free_var[tn].size()<=i ){ + std::stringstream oss; + oss << tn; + std::string typ_name = oss.str(); + while( typ_name[0]=='(' ){ + typ_name.erase( typ_name.begin() ); + } + std::stringstream os; + os << typ_name[0] << i; + Node x = NodeManager::currentNM()->mkBoundVar( os.str().c_str(), tn ); + d_free_var_num[x] = d_free_var[tn].size(); + d_free_var[tn].push_back( x ); + } + return d_free_var[tn][i]; +} + + + +Node ConjectureGenerator::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ) { + if( n.getKind()==BOUND_VARIABLE ){ + std::map< TNode, TNode >::iterator it = subs.find( n ); + if( it==subs.end() ){ + TypeNode tn = n.getType(); + //allocate variable + unsigned vn = var_count[tn]; + var_count[tn]++; + subs[n] = getFreeVar( tn, vn ); + return subs[n]; + }else{ + return it->second; + } + }else{ + std::vector< Node > children; + if( n.getKind()!=EQUAL ){ + if( n.hasOperator() ){ + TNode op = n.getOperator(); + if( !d_tge.isRelevantFunc( op ) ){ + return Node::null(); + } + children.push_back( op ); + }else{ + return Node::null(); + } + } + for( unsigned i=0; imkNode( n.getKind(), children ); + } +} + +bool ConjectureGenerator::isHandledTerm( TNode n ){ + return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM ); +} + +Node ConjectureGenerator::getGroundEqc( TNode r ) { + std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r ); + return it!=d_ground_eqc_map.end() ? it->second : Node::null(); +} + +bool ConjectureGenerator::isGroundEqc( TNode r ) { + return d_ground_eqc_map.find( r )!=d_ground_eqc_map.end(); +} + +bool ConjectureGenerator::isGroundTerm( TNode n ) { + return std::find( d_ground_terms.begin(), d_ground_terms.end(), n )!=d_ground_terms.end(); +} + +bool ConjectureGenerator::needsCheck( Theory::Effort e ) { + // synchonized with instantiation engine + return d_quantEngine->getInstWhenNeedsCheck( e ); +} + +bool ConjectureGenerator::hasEnumeratedUf( Node n ) { + if( options::conjectureGenGtEnum()>0 ){ + std::map< Node, bool >::iterator it = d_uf_enum.find( n.getOperator() ); + if( it==d_uf_enum.end() ){ + d_uf_enum[n.getOperator()] = true; + std::vector< Node > lem; + getEnumeratePredUfTerm( n, options::conjectureGenGtEnum(), lem ); + if( !lem.empty() ){ + for( unsigned j=0; jaddLemma( lem[j], false ); + d_hasAddedLemma = true; + } + return false; + } + } + } + return true; +} + +void ConjectureGenerator::reset_round( Theory::Effort e ) { + +} + +void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) { + if( quant_e==QuantifiersEngine::QEFFORT_STANDARD ){ + d_fullEffortCount++; + if( d_fullEffortCount%optFullCheckFrequency()==0 ){ + d_hasAddedLemma = false; + d_tge.d_cg = this; + double clSet = 0; + if( Trace.isOn("sg-engine") ){ + clSet = double(clock())/double(CLOCKS_PER_SEC); + Trace("sg-engine") << "---Conjecture Engine Round, effort = " << e << "---" << std::endl; + } + eq::EqualityEngine * ee = getEqualityEngine(); + d_conj_count = 0; + + Trace("sg-proc") << "Get eq classes..." << std::endl; + d_op_arg_index.clear(); + d_ground_eqc_map.clear(); + d_bool_eqc[0] = Node::null(); + d_bool_eqc[1] = Node::null(); + std::vector< TNode > eqcs; + d_em.clear(); + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee ); + while( !eqcs_i.isFinished() ){ + TNode r = (*eqcs_i); + eqcs.push_back( r ); + if( r.getType().isBoolean() ){ + if( areEqual( r, getTermDatabase()->d_true ) ){ + d_ground_eqc_map[r] = getTermDatabase()->d_true; + d_bool_eqc[0] = r; + }else if( areEqual( r, getTermDatabase()->d_false ) ){ + d_ground_eqc_map[r] = getTermDatabase()->d_false; + d_bool_eqc[1] = r; + } + } + d_em[r] = eqcs.size(); + eq::EqClassIterator ieqc_i = eq::EqClassIterator( r, ee ); + while( !ieqc_i.isFinished() ){ + TNode n = (*ieqc_i); + if( getTermDatabase()->hasTermCurrent( n ) ){ + if( isHandledTerm( n ) ){ + d_op_arg_index[r].addTerm( this, n ); + } + } + ++ieqc_i; + } + ++eqcs_i; + } + Assert( !d_bool_eqc[0].isNull() ); + Assert( !d_bool_eqc[1].isNull() ); + d_urelevant_terms.clear(); + Trace("sg-proc") << "...done get eq classes" << std::endl; + + Trace("sg-proc") << "Determine ground EQC..." << std::endl; + bool success; + do{ + success = false; + for( unsigned i=0; i args; + Trace("sg-pat-debug") << "******* Get ground term for " << r << std::endl; + Node n; + if( getTermDatabase()->isInductionTerm( r ) ){ + n = d_op_arg_index[r].getGroundTerm( this, args ); + }else{ + n = r; + } + if( !n.isNull() ){ + Trace("sg-pat") << "Ground term for eqc " << r << " : " << std::endl; + Trace("sg-pat") << " " << n << std::endl; + d_ground_eqc_map[r] = n; + success = true; + }else{ + Trace("sg-pat-debug") << "...could not find ground term." << std::endl; + } + } + } + }while( success ); + //also get ground terms + d_ground_terms.clear(); + for( unsigned i=0; id_false ); + eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee ); + while( !eqc_i.isFinished() ){ + TNode n = (*eqc_i); + if( getTermDatabase()->hasTermCurrent( n ) && !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){ + if( firstTime ){ + Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl; + firstTime = false; + } + if( n.hasOperator() ){ + Trace("sg-gen-eqc") << " (" << n.getOperator(); + getTermDatabase()->computeArgReps( n ); + for( unsigned i=0; id_arg_reps[n].size(); i++ ){ + Trace("sg-gen-eqc") << " e" << d_em[getTermDatabase()->d_arg_reps[n][i]]; + } + Trace("sg-gen-eqc") << ") :: " << n << std::endl; + }else{ + Trace("sg-gen-eqc") << " " << n << std::endl; + } + } + ++eqc_i; + } + if( !firstTime ){ + Trace("sg-gen-eqc") << "}" << std::endl; + //print out ground term + std::map< TNode, Node >::iterator it = d_ground_eqc_map.find( r ); + if( it!=d_ground_eqc_map.end() ){ + Trace("sg-gen-eqc") << "- Ground term : " << it->second << std::endl; + } + } + } + } + + Trace("sg-proc") << "Compute relevant eqc..." << std::endl; + d_tge.d_relevant_eqc[0].clear(); + d_tge.d_relevant_eqc[1].clear(); + for( unsigned i=0; i::iterator it = d_ground_eqc_map.find( r ); + unsigned index = 1; + if( it==d_ground_eqc_map.end() ){ + index = 0; + } + //based on unproven conjectures? TODO + d_tge.d_relevant_eqc[index].push_back( r ); + } + Trace("sg-gen-tg-debug") << "Initial relevant eqc : "; + for( unsigned i=0; i provenConj; + quantifiers::FirstOrderModel* m = d_quantEngine->getModel(); + for( int i=0; igetNumAssertedQuantifiers(); i++ ){ + Node q = m->getAssertedQuantifier( i ); + Trace("thm-db-debug") << "Is " << q << " a relevant theorem?" << std::endl; + Node conjEq; + if( q[1].getKind()==EQUAL ){ + bool isSubsume = false; + bool inEe = false; + for( unsigned r=0; r<2; r++ ){ + TNode nl = q[1][r==0 ? 0 : 1]; + TNode nr = q[1][r==0 ? 1 : 0]; + Node eq = nl.eqNode( nr ); + if( r==1 || std::find( d_conjectures.begin(), d_conjectures.end(), q )==d_conjectures.end() ){ + //must make it canonical + std::map< TypeNode, unsigned > var_count; + std::map< TNode, TNode > subs; + Trace("sg-proc-debug") << "get canonical " << eq << std::endl; + eq = getCanonicalTerm( eq, var_count, subs ); + } + if( !eq.isNull() ){ + if( r==0 ){ + inEe = d_ee_conjectures.find( q[1] )!=d_ee_conjectures.end(); + if( !inEe ){ + //add to universal equality engine + Node nl = getUniversalRepresentative( eq[0], true ); + Node nr = getUniversalRepresentative( eq[1], true ); + if( areUniversalEqual( nl, nr ) ){ + isSubsume = true; + //set inactive (will be ignored by other modules) + d_quantEngine->getModel()->setQuantifierActive( q, false ); + }else{ + Node exp; + d_ee_conjectures[q[1]] = true; + d_uequalityEngine.assertEquality( nl.eqNode( nr ), true, exp ); + } + } + Trace("sg-conjecture") << "*** CONJECTURE : currently proven" << (isSubsume ? " and subsumed" : ""); + Trace("sg-conjecture") << " : " << q[1] << std::endl; + provenConj.push_back( q ); + } + if( !isSubsume ){ + Trace("thm-db-debug") << "Adding theorem to database " << eq[0] << " == " << eq[1] << std::endl; + d_thm_index.addTheorem( eq[0], eq[1] ); + }else{ + break; + } + }else{ + break; + } + } + } + } + //examine status of other conjectures + for( unsigned i=0; i sk; + //getTermDatabase()->getSkolemConstants( q, sk, true ); + Trace("sg-conjecture") << " CONJECTURE : "; + std::vector< Node > ce; + for( unsigned j=0; jd_skolem_constants[q].size(); j++ ){ + TNode k = getTermDatabase()->d_skolem_constants[q][j]; + TNode rk = getRepresentative( k ); + std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( rk ); + //check if it is a ground term + if( git==d_ground_eqc_map.end() ){ + Trace("sg-conjecture") << "ACTIVE : " << q; + if( Trace.isOn("sg-gen-eqc") ){ + Trace("sg-conjecture") << " { "; + for( unsigned k=0; kd_skolem_constants[q].size(); k++ ){ Trace("sg-conjecture") << getTermDatabase()->d_skolem_constants[q][k] << ( j==k ? "*" : "" ) << " "; } + Trace("sg-conjecture") << "}"; + } + Trace("sg-conjecture") << std::endl; + disproven = false; + break; + }else{ + ce.push_back( git->second ); + } + } + if( disproven ){ + Trace("sg-conjecture") << "disproven : " << q << " : "; + for( unsigned i=0; i " << ce[i] << " "; + } + Trace("sg-conjecture") << std::endl; + } + } + } + Trace("thm-db") << "Theorem database is : " << std::endl; + d_thm_index.debugPrint( "thm-db" ); + Trace("thm-db") << std::endl; + Trace("sg-proc") << "...done build theorem index" << std::endl; + + + //clear patterns + d_patterns.clear(); + d_pattern_var_id.clear(); + d_pattern_var_duplicate.clear(); + d_pattern_is_normal.clear(); + d_pattern_is_relevant.clear(); + d_pattern_fun_id.clear(); + d_pattern_fun_sum.clear(); + d_rel_patterns.clear(); + d_rel_pattern_var_sum.clear(); + d_rel_pattern_typ_index.clear(); + d_rel_pattern_subs_index.clear(); + + unsigned rel_term_count = 0; + std::map< TypeNode, unsigned > rt_var_max; + std::vector< TypeNode > rt_types; + std::map< TypeNode, std::map< int, std::vector< Node > > > conj_lhs; + unsigned addedLemmas = 0; + for( unsigned depth=1; depth<=3; depth++ ){ + Trace("sg-proc") << "Generate relevant LHS at depth " << depth << "..." << std::endl; + Trace("sg-rel-term") << "Relevant terms of depth " << depth << " : " << std::endl; + //set up environment + d_tge.d_var_id.clear(); + d_tge.d_var_limit.clear(); + d_tge.reset( depth, true, TypeNode::null() ); + while( d_tge.getNextTerm() ){ + //construct term + Node nn = d_tge.getTerm(); + if( !options::conjectureFilterCanonical() || considerTermCanon( nn, true ) ){ + rel_term_count++; + Trace("sg-rel-term") << "*** Relevant term : "; + d_tge.debugPrint( "sg-rel-term", "sg-rel-term-debug2" ); + Trace("sg-rel-term") << std::endl; + + for( unsigned r=0; r<2; r++ ){ + Trace("sg-rel-term-debug") << "...from equivalence classes (" << r << ") : "; + int index = d_tge.d_ccand_eqc[r].size()-1; + for( unsigned j=0; j typ_to_subs_index; + std::vector< TNode > gsubs_vars; + for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){ + if( it->second>0 ){ + typ_to_subs_index[it->first] = sum; + sum += it->second; + for( unsigned i=0; isecond; i++ ){ + gsubs_vars.push_back( getFreeVar( it->first, i ) ); + } + } + } + d_rel_pattern_var_sum[nn] = sum; + //register the pattern + registerPattern( nn, tnn ); + Assert( d_pattern_is_normal[nn] ); + Trace("sg-gen-tg-debug") << "...done collect pattern information" << std::endl; + + //record information about types + Trace("sg-gen-tg-debug") << "Collect type information..." << std::endl; + PatternTypIndex * pti = &d_rel_pattern_typ_index; + for( std::map< TypeNode, unsigned >::iterator it = d_tge.d_var_id.begin(); it != d_tge.d_var_id.end(); ++it ){ + pti = &pti->d_children[it->first][it->second]; + //record maximum + if( rt_var_max.find( it->first )==rt_var_max.end() || it->second>rt_var_max[it->first] ){ + rt_var_max[it->first] = it->second; + } + } + if( std::find( rt_types.begin(), rt_types.end(), tnn )==rt_types.end() ){ + rt_types.push_back( tnn ); + } + pti->d_terms.push_back( nn ); + Trace("sg-gen-tg-debug") << "...done collect type information" << std::endl; + + Trace("sg-gen-tg-debug") << "Build substitutions for ground EQC..." << std::endl; + std::vector< TNode > gsubs_terms; + gsubs_terms.resize( gsubs_vars.size() ); + int index = d_tge.d_ccand_eqc[1].size()-1; + for( unsigned j=0; j > subs; + std::map< TNode, bool > rev_subs; + //only get ground terms + unsigned mode = 2; + d_tge.resetMatching( r, mode ); + while( d_tge.getNextMatch( r, subs, rev_subs ) ){ + //we will be building substitutions + bool firstTime = true; + for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator it = subs.begin(); it != subs.end(); ++it ){ + unsigned tindex = typ_to_subs_index[it->first]; + for( std::map< unsigned, TNode >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + if( !firstTime ){ + Trace("sg-rel-term-debug") << ", "; + }else{ + firstTime = false; + Trace("sg-rel-term-debug") << " "; + } + Trace("sg-rel-term-debug") << it->first << ":x" << it2->first << " -> " << it2->second; + Assert( tindex+it2->firstfirst] = it2->second; + } + } + Trace("sg-rel-term-debug") << std::endl; + d_rel_pattern_subs_index[nn].addSubstitution( r, gsubs_vars, gsubs_terms ); + } + } + Trace("sg-gen-tg-debug") << "...done build substitutions for ground EQC" << std::endl; + }else{ + Trace("sg-gen-tg-debug") << "> not canonical : " << nn << std::endl; + } + } + Trace("sg-proc") << "...done generate terms at depth " << depth << std::endl; + Trace("sg-stats") << "--------> Total LHS of depth " << depth << " : " << rel_term_count << std::endl; + //Trace("conjecture-count") << "Total LHS of depth " << depth << " : " << conj_lhs[depth].size() << std::endl; + + /* test... + for( unsigned i=0; i::iterator it = rt_var_max.begin(); it != rt_var_max.end(); ++it ){ + d_tge.d_var_id[ it->first ] = it->second; + d_tge.d_var_limit[ it->first ] = it->second; + } + std::random_shuffle( rt_types.begin(), rt_types.end() ); + std::map< TypeNode, std::vector< Node > > conj_rhs; + for( unsigned i=0; i >::iterator it = conj_rhs.begin(); it != conj_rhs.end(); ++it ){ + for( unsigned j=0; jsecond.size(); j++ ){ + for( unsigned k=0; kfirst][lhs_depth].size(); k++ ){ + processCandidateConjecture( conj_lhs[it->first][lhs_depth][k], it->second[j], lhs_depth, rdepth ); + } + } + } + flushWaitingConjectures( addedLemmas, lhs_depth, depth ); + } + } + } + if( (int)addedLemmas>=options::conjectureGenPerRound() ){ + break; + } + } + if( (int)addedLemmas>=options::conjectureGenPerRound() ){ + break; + } + } + Trace("sg-stats") << "Total conjectures considered : " << d_conj_count << std::endl; + if( Trace.isOn("thm-ee") ){ + Trace("thm-ee") << "Universal equality engine is : " << std::endl; + eq::EqClassesIterator ueqcs_i = eq::EqClassesIterator( &d_uequalityEngine ); + while( !ueqcs_i.isFinished() ){ + TNode r = (*ueqcs_i); + bool firstTime = true; + TNode rr = getUniversalRepresentative( r ); + Trace("thm-ee") << " " << rr; + Trace("thm-ee") << " : { "; + eq::EqClassIterator ueqc_i = eq::EqClassIterator( r, &d_uequalityEngine ); + while( !ueqc_i.isFinished() ){ + TNode n = (*ueqc_i); + if( rr!=n ){ + if( firstTime ){ + Trace("thm-ee") << std::endl; + firstTime = false; + } + Trace("thm-ee") << " " << n << std::endl; + } + ++ueqc_i; + } + if( !firstTime ){ Trace("thm-ee") << " "; } + Trace("thm-ee") << "}" << std::endl; + ++ueqcs_i; + } + Trace("thm-ee") << std::endl; + } + if( Trace.isOn("sg-engine") ){ + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Trace("sg-engine") << "Finished conjecture generator, time = " << (clSet2-clSet) << std::endl; + } + } + } +} + +unsigned ConjectureGenerator::flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ) { + if( !d_waiting_conjectures_lhs.empty() ){ + Trace("sg-proc") << "Generated " << d_waiting_conjectures_lhs.size() << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl; + if( (int)addedLemmas indices; + for( unsigned i=0; i=optFilterScoreThreshold() ){ + //we have determined a relevant subgoal + Node lhs = d_waiting_conjectures_lhs[i]; + Node rhs = d_waiting_conjectures_rhs[i]; + if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){ + //skip + }else{ + Trace("sg-engine") << "*** Consider conjecture : " << lhs << " == " << rhs << std::endl; + Trace("sg-engine-debug") << " score : " << d_waiting_conjectures_score[i] << std::endl; + if( optStatsOnly() ){ + d_conj_count++; + }else{ + std::vector< Node > bvs; + for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[lhs].begin(); it != d_pattern_var_id[lhs].end(); ++it ){ + for( unsigned i=0; i<=it->second; i++ ){ + bvs.push_back( getFreeVar( it->first, i ) ); + } + } + Node rsg; + if( !bvs.empty() ){ + Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvs ); + rsg = NodeManager::currentNM()->mkNode( FORALL, bvl, lhs.eqNode( rhs ) ); + }else{ + rsg = lhs.eqNode( rhs ); + } + rsg = Rewriter::rewrite( rsg ); + d_conjectures.push_back( rsg ); + d_eq_conjectures[lhs].push_back( rhs ); + d_eq_conjectures[rhs].push_back( lhs ); + + Node lem = NodeManager::currentNM()->mkNode( OR, rsg.negate(), rsg ); + d_quantEngine->addLemma( lem, false ); + d_quantEngine->addRequirePhase( rsg, false ); + addedLemmas++; + if( (int)addedLemmas>=options::conjectureGenPerRound() ){ + break; + } + } + } + } + } + Trace("sg-proc") << "...have now added " << addedLemmas << " conjecture lemmas." << std::endl; + if( optStatsOnly() ){ + Trace("sg-stats") << "Generated " << (d_conj_count-prevCount) << " conjectures at depth " << ldepth << "/" << rdepth << "." << std::endl; + } + } + d_waiting_conjectures_lhs.clear(); + d_waiting_conjectures_rhs.clear(); + d_waiting_conjectures_score.clear(); + d_waiting_conjectures.clear(); + } + return addedLemmas; +} + +void ConjectureGenerator::registerQuantifier( Node q ) { + +} + +void ConjectureGenerator::assertNode( Node n ) { + +} + +bool ConjectureGenerator::considerTermCanon( Node ln, bool genRelevant ){ + if( !ln.isNull() ){ + //do not consider if it is non-canonical, and either: + // (1) we are not generating relevant terms, or + // (2) its canonical form is a generalization. + TNode lnr = getUniversalRepresentative( ln, true ); + if( lnr==ln ){ + markReportedCanon( ln ); + }else if( !genRelevant || isGeneralization( lnr, ln ) ){ + Trace("sg-gen-consider-term") << "Do not consider term, " << ln << " is not canonical representation (which is " << lnr << ")." << std::endl; + return false; + } + } + Trace("sg-gen-tg-debug") << "Will consider term canon " << ln << std::endl; + Trace("sg-gen-consider-term-debug") << std::endl; + return true; +} + +unsigned ConjectureGenerator::collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs, + std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ){ + if( pat.hasOperator() ){ + funcs[pat.getOperator()]++; + if( !d_tge.isRelevantFunc( pat.getOperator() ) ){ + d_pattern_is_relevant[opat] = false; + } + unsigned sum = 1; + for( unsigned i=0; i1 ){ + //duplicate variable + d_pattern_var_duplicate[opat]++; + }else{ + //check for max/min + TypeNode tn = pat.getType(); + unsigned vn = d_free_var_num[pat]; + std::map< TypeNode, unsigned >::iterator it = mnvn.find( tn ); + if( it!=mnvn.end() ){ + if( vnsecond ){ + d_pattern_is_normal[opat] = false; + mnvn[tn] = vn; + }else if( vn>mxvn[tn] ){ + if( vn!=mxvn[tn]+1 ){ + d_pattern_is_normal[opat] = false; + } + mxvn[tn] = vn; + } + }else{ + //first variable of this type + mnvn[tn] = vn; + mxvn[tn] = vn; + } + } + }else{ + d_pattern_is_relevant[opat] = false; + } + return 1; + } +} + +void ConjectureGenerator::registerPattern( Node pat, TypeNode tpat ) { + if( std::find( d_patterns[tpat].begin(), d_patterns[tpat].end(), pat )==d_patterns[tpat].end() ){ + d_patterns[TypeNode::null()].push_back( pat ); + d_patterns[tpat].push_back( pat ); + + Assert( d_pattern_fun_id.find( pat )==d_pattern_fun_id.end() ); + Assert( d_pattern_var_id.find( pat )==d_pattern_var_id.end() ); + + //collect functions + std::map< TypeNode, unsigned > mnvn; + d_pattern_fun_sum[pat] = collectFunctions( pat, pat, d_pattern_fun_id[pat], mnvn, d_pattern_var_id[pat] ); + if( d_pattern_is_normal.find( pat )==d_pattern_is_normal.end() ){ + d_pattern_is_normal[pat] = true; + } + if( d_pattern_is_relevant.find( pat )==d_pattern_is_relevant.end() ){ + d_pattern_is_relevant[pat] = true; + } + } +} + +bool ConjectureGenerator::isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ) { + if( patg.getKind()==BOUND_VARIABLE ){ + std::map< TNode, TNode >::iterator it = subs.find( patg ); + if( it!=subs.end() ){ + return it->second==pat; + }else{ + subs[patg] = pat; + return true; + } + }else{ + Assert( patg.hasOperator() ); + if( !pat.hasOperator() || patg.getOperator()!=pat.getOperator() ){ + return false; + }else{ + Assert( patg.getNumChildren()==pat.getNumChildren() ); + for( unsigned i=0; i& fv ) { + if( n.getKind()==BOUND_VARIABLE ){ + if( std::find( fv.begin(), fv.end(), n )==fv.end() ){ + fv.push_back( n ); + return 0; + }else{ + return 1; + } + }else{ + int depth = 1; + for( unsigned i=0; i::iterator it = d_typ_pred.find( tn ); + if( it==d_typ_pred.end() ){ + TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->booleanType() ); + Node op = NodeManager::currentNM()->mkSkolem( "PE", op_tn, "was created by conjecture ground term enumerator." ); + d_typ_pred[tn] = op; + return op; + }else{ + return it->second; + } +} + +void ConjectureGenerator::getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ) { + if( n.getNumChildren()>0 ){ + std::vector< int > vec; + for( unsigned i=0; igetEnumerateTerm( n[index].getType(), vec[index]+1 ).isNull() ){ + vec[index]++; + vec_sum++; + vec.push_back( size_limit - vec_sum ); + }else{ + vec_sum -= vec[index]; + vec[index] = 0; + index++; + if( index==n.getNumChildren() ){ + success = false; + } + } + } + if( success ){ + if( vec.size()==n.getNumChildren() ){ + Node lc = getTermDatabase()->getEnumerateTerm( n[vec.size()-1].getType(), vec[vec.size()-1] ); + if( !lc.isNull() ){ + for( unsigned i=0; i children; + children.push_back( n.getOperator() ); + for( unsigned i=0; i<(vec.size()-1); i++ ){ + Node nn = getTermDatabase()->getEnumerateTerm( n[i].getType(), vec[i] ); + Assert( !nn.isNull() ); + Assert( nn.getType()==n[i].getType() ); + children.push_back( nn ); + } + children.push_back( lc ); + Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children ); + Trace("sg-gt-enum") << "Ground term enumerate : " << n << std::endl; + terms.push_back( n ); + } + vec.pop_back(); + index = 0; + } + }else{ + if( terms.size()>last_size ){ + last_size = terms.size(); + size_limit++; + for( unsigned i=0; i& terms ) { + std::vector< Node > uf_terms; + getEnumerateUfTerm( n, num, uf_terms ); + Node p = getPredicateForType( n.getType() ); + for( unsigned i=0; imkNode( APPLY_UF, p, uf_terms[i] ) ); + } +} + +void ConjectureGenerator::processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ) { + int score = considerCandidateConjecture( lhs, rhs ); + if( score>0 ){ + Trace("sg-conjecture") << "* Candidate conjecture : " << lhs << " == " << rhs << std::endl; + Trace("sg-conjecture-debug") << " LHS, RHS generalization depth : " << lhs_depth << ", " << rhs_depth << std::endl; + Trace("sg-conjecture-debug") << " confirmed = " << d_subs_confirmCount << ", #witnesses range = " << d_subs_confirmWitnessRange.size() << "." << std::endl; + Trace("sg-conjecture-debug") << " #witnesses for "; + bool firstTime = true; + for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ + if( !firstTime ){ + Trace("sg-conjecture-debug") << ", "; + } + Trace("sg-conjecture-debug") << it->first << " : " << it->second.size(); + //if( it->second.size()==1 ){ + // Trace("sg-conjecture-debug") << " (" << it->second[0] << ")"; + //} + Trace("sg-conjecture-debug2") << " ("; + for( unsigned j=0; jsecond.size(); j++ ){ + if( j>0 ){ Trace("sg-conjecture-debug2") << " "; } + Trace("sg-conjecture-debug2") << d_ground_eqc_map[it->second[j]]; + } + Trace("sg-conjecture-debug2") << ")"; + firstTime = false; + } + Trace("sg-conjecture-debug") << std::endl; + Trace("sg-conjecture-debug") << " unknown = " << d_subs_unkCount << std::endl; + //Assert( getUniversalRepresentative( rhs )==rhs ); + //Assert( getUniversalRepresentative( lhs )==lhs ); + d_waiting_conjectures_lhs.push_back( lhs ); + d_waiting_conjectures_rhs.push_back( rhs ); + d_waiting_conjectures_score.push_back( score ); + d_waiting_conjectures[lhs].push_back( rhs ); + d_waiting_conjectures[rhs].push_back( lhs ); + } +} + +int ConjectureGenerator::considerCandidateConjecture( TNode lhs, TNode rhs ) { + Assert( lhs.getType()==rhs.getType() ); + + Trace("sg-cconj-debug") << "Consider candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl; + if( lhs==rhs ){ + Trace("sg-cconj-debug") << " -> trivial." << std::endl; + return -1; + }else{ + if( lhs.getKind()==APPLY_CONSTRUCTOR && rhs.getKind()==APPLY_CONSTRUCTOR ){ + Trace("sg-cconj-debug") << " -> irrelevant by syntactic analysis." << std::endl; + return -1; + } + //variables of LHS must subsume variables of RHS + for( std::map< TypeNode, unsigned >::iterator it = d_pattern_var_id[rhs].begin(); it != d_pattern_var_id[rhs].end(); ++it ){ + std::map< TypeNode, unsigned >::iterator itl = d_pattern_var_id[lhs].find( it->first ); + if( itl!=d_pattern_var_id[lhs].end() ){ + if( itl->secondsecond ){ + Trace("sg-cconj-debug") << " -> variables of sort " << it->first << " are not subsumed." << std::endl; + return -1; + }else{ + Trace("sg-cconj-debug2") << " variables of sort " << it->first << " are : " << itl->second << " vs " << it->second << std::endl; + } + }else{ + Trace("sg-cconj-debug") << " -> has no variables of sort " << it->first << "." << std::endl; + return -1; + } + } + + //currently active conjecture? + std::map< Node, std::vector< Node > >::iterator iteq = d_eq_conjectures.find( lhs ); + if( iteq!=d_eq_conjectures.end() ){ + if( std::find( iteq->second.begin(), iteq->second.end(), rhs )!=iteq->second.end() ){ + Trace("sg-cconj-debug") << " -> this conjecture is already active." << std::endl; + return -1; + } + } + //current a waiting conjecture? + std::map< Node, std::vector< Node > >::iterator itw = d_waiting_conjectures.find( lhs ); + if( itw!=d_waiting_conjectures.end() ){ + if( std::find( itw->second.begin(), itw->second.end(), rhs )!=itw->second.end() ){ + Trace("sg-cconj-debug") << " -> already are considering this conjecture." << std::endl; + return -1; + } + } + //check if canonical representation (should be, but for efficiency this is not guarenteed) + //if( options::conjectureFilterCanonical() && ( getUniversalRepresentative( lhs )!=lhs || getUniversalRepresentative( rhs )!=rhs ) ){ + // Trace("sg-cconj") << " -> after processing, not canonical." << std::endl; + // return -1; + //} + + int score; + bool scoreSet = false; + + Trace("sg-cconj") << "Consider possible candidate conjecture : " << lhs << " == " << rhs << "?" << std::endl; + //find witness for counterexample, if possible + if( options::conjectureFilterModel() ){ + Assert( d_rel_pattern_var_sum.find( lhs )!=d_rel_pattern_var_sum.end() ); + Trace("sg-cconj-debug") << "Notify substitutions over " << d_rel_pattern_var_sum[lhs] << " variables." << std::endl; + std::map< TNode, TNode > subs; + d_subs_confirmCount = 0; + d_subs_confirmWitnessRange.clear(); + d_subs_confirmWitnessDomain.clear(); + d_subs_unkCount = 0; + if( !d_rel_pattern_subs_index[lhs].notifySubstitutions( this, subs, rhs, d_rel_pattern_var_sum[lhs] ) ){ + Trace("sg-cconj") << " -> found witness that falsifies the conjecture." << std::endl; + return -1; + } + //score is the minimum number of distinct substitutions for a variable + for( std::map< TNode, std::vector< TNode > >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ + int num = (int)it->second.size(); + if( !scoreSet || num >::iterator it = d_subs_confirmWitnessDomain.begin(); it != d_subs_confirmWitnessDomain.end(); ++it ){ + Trace("sg-cconj") << " #witnesses for " << it->first << " : " << it->second.size() << std::endl; + } + }else{ + score = 1; + } + + Trace("sg-cconj") << " -> SUCCESS." << std::endl; + Trace("sg-cconj") << " score : " << score << std::endl; + + return score; + } +} + +bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ) { + if( Trace.isOn("sg-cconj-debug") ){ + Trace("sg-cconj-debug") << "Ground eqc for LHS : " << glhs << ", based on substituion: " << std::endl; + for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ + Assert( getRepresentative( it->second )==it->second ); + Trace("sg-cconj-debug") << " " << it->first << " -> " << it->second << std::endl; + } + } + Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl; + //get the representative of rhs with substitution subs + TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true ); + Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl; + if( !grhs.isNull() ){ + if( glhs!=grhs ){ + Trace("sg-cconj-debug") << "Ground eqc for RHS : " << grhs << std::endl; + //check based on ground terms + std::map< TNode, Node >::iterator itl = d_ground_eqc_map.find( glhs ); + if( itl!=d_ground_eqc_map.end() ){ + std::map< TNode, Node >::iterator itr = d_ground_eqc_map.find( grhs ); + if( itr!=d_ground_eqc_map.end() ){ + Trace("sg-cconj-debug") << "We have ground terms " << itl->second << " and " << itr->second << "." << std::endl; + if( itl->second.isConst() && itr->second.isConst() ){ + Trace("sg-cconj-debug") << "...disequal constants." << std::endl; + Trace("sg-cconj-witness") << " Witness of falsification : " << itl->second << " != " << itr->second << ", substutition is : " << std::endl; + for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ + Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl; + } + return false; + } + } + } + } + Trace("sg-cconj-debug") << "RHS is identical." << std::endl; + bool isGroundSubs = true; + for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ + std::map< TNode, Node >::iterator git = d_ground_eqc_map.find( it->second ); + if( git==d_ground_eqc_map.end() ){ + isGroundSubs = false; + break; + } + } + if( isGroundSubs ){ + if( glhs==grhs ){ + Trace("sg-cconj-witness") << " Witnessed " << glhs << " == " << grhs << ", substutition is : " << std::endl; + for( std::map< TNode, TNode >::iterator it = subs.begin(); it != subs.end(); ++it ){ + Trace("sg-cconj-witness") << " " << it->first << " -> " << it->second << std::endl; + if( std::find( d_subs_confirmWitnessDomain[it->first].begin(), d_subs_confirmWitnessDomain[it->first].end(), it->second )==d_subs_confirmWitnessDomain[it->first].end() ){ + d_subs_confirmWitnessDomain[it->first].push_back( it->second ); + } + } + d_subs_confirmCount++; + if( std::find( d_subs_confirmWitnessRange.begin(), d_subs_confirmWitnessRange.end(), glhs )==d_subs_confirmWitnessRange.end() ){ + d_subs_confirmWitnessRange.push_back( glhs ); + } + }else{ + if( optFilterUnknown() ){ + Trace("sg-cconj-debug") << "...ground substitution giving terms that are neither equal nor disequal." << std::endl; + return false; + } + } + } + }else{ + Trace("sg-cconj-debug") << "(could not ground eqc for RHS)." << std::endl; + } + return true; +} + + + + + + +void TermGenerator::reset( TermGenEnv * s, TypeNode tn ) { + Assert( d_children.empty() ); + d_typ = tn; + d_status = 0; + d_status_num = 0; + d_children.clear(); + Trace("sg-gen-tg-debug2") << "...add to context " << this << std::endl; + d_id = s->d_tg_id; + s->changeContext( true ); +} + +bool TermGenerator::getNextTerm( TermGenEnv * s, unsigned depth ) { + if( Trace.isOn("sg-gen-tg-debug2") ){ + Trace("sg-gen-tg-debug2") << this << " getNextTerm depth " << depth << " : status = " << d_status << ", num = " << d_status_num; + if( d_status==5 ){ + TNode f = s->getTgFunc( d_typ, d_status_num ); + Trace("sg-gen-tg-debug2") << ", f = " << f; + Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size(); + Trace("sg-gen-tg-debug2") << ", childNum = " << d_status_child_num; + Trace("sg-gen-tg-debug2") << ", #children = " << d_children.size(); + } + Trace("sg-gen-tg-debug2") << std::endl; + } + + if( d_status==0 ){ + d_status++; + if( !d_typ.isNull() ){ + if( s->allowVar( d_typ ) ){ + //allocate variable + d_status_num = s->d_var_id[d_typ]; + s->addVar( d_typ ); + Trace("sg-gen-tg-debug2") << this << " ...return unique var #" << d_status_num << std::endl; + return s->considerCurrentTerm() ? true : getNextTerm( s, depth ); + }else{ + //check allocating new variable + d_status++; + d_status_num = -1; + if( s->d_gen_relevant_terms ){ + s->d_tg_gdepth++; + } + return getNextTerm( s, depth ); + } + }else{ + d_status = 4; + d_status_num = -1; + return getNextTerm( s, depth ); + } + }else if( d_status==2 ){ + //cleanup previous information + //if( d_status_num>=0 ){ + // s->d_var_eq_tg[d_status_num].pop_back(); + //} + //check if there is another variable + if( (d_status_num+1)<(int)s->getNumTgVars( d_typ ) ){ + d_status_num++; + //we have equated two variables + //s->d_var_eq_tg[d_status_num].push_back( d_id ); + Trace("sg-gen-tg-debug2") << this << "...consider other var #" << d_status_num << std::endl; + return s->considerCurrentTerm() ? true : getNextTerm( s, depth ); + }else{ + if( s->d_gen_relevant_terms ){ + s->d_tg_gdepth--; + } + d_status++; + return getNextTerm( s, depth ); + } + }else if( d_status==4 ){ + d_status++; + if( depth>0 && (d_status_num+1)<(int)s->getNumTgFuncs( d_typ ) ){ + d_status_num++; + d_status_child_num = 0; + Trace("sg-gen-tg-debug2") << this << "...consider function " << s->getTgFunc( d_typ, d_status_num ) << std::endl; + s->d_tg_gdepth++; + if( !s->considerCurrentTerm() ){ + s->d_tg_gdepth--; + //don't consider this function + d_status--; + }else{ + //we have decided on a function application + } + return getNextTerm( s, depth ); + }else{ + //do not choose function applications at depth 0 + d_status++; + return getNextTerm( s, depth ); + } + }else if( d_status==5 ){ + //iterating over arguments + TNode f = s->getTgFunc( d_typ, d_status_num ); + if( d_status_child_num<0 ){ + //no more arguments + s->d_tg_gdepth--; + d_status--; + return getNextTerm( s, depth ); + }else if( d_status_child_num==(int)s->d_func_args[f].size() ){ + d_status_child_num--; + return s->considerCurrentTermCanon( d_id ) ? true : getNextTerm( s, depth ); + //return true; + }else{ + Assert( d_status_child_num<(int)s->d_func_args[f].size() ); + if( d_status_child_num==(int)d_children.size() ){ + d_children.push_back( s->d_tg_id ); + Assert( s->d_tg_alloc.find( s->d_tg_id )==s->d_tg_alloc.end() ); + s->d_tg_alloc[d_children[d_status_child_num]].reset( s, s->d_func_args[f][d_status_child_num] ); + return getNextTerm( s, depth ); + }else{ + Assert( d_status_child_num+1==(int)d_children.size() ); + if( s->d_tg_alloc[d_children[d_status_child_num]].getNextTerm( s, depth-1 ) ){ + d_status_child_num++; + return getNextTerm( s, depth ); + }else{ + d_children.pop_back(); + d_status_child_num--; + return getNextTerm( s, depth ); + } + } + } + }else if( d_status==1 || d_status==3 ){ + if( d_status==1 ){ + s->removeVar( d_typ ); + Assert( d_status_num==(int)s->d_var_id[d_typ] ); + //check if there is only one feasible equivalence class. if so, don't make pattern any more specific. + //unsigned i = s->d_ccand_eqc[0].size()-1; + //if( s->d_ccand_eqc[0][i].size()==1 && s->d_ccand_eqc[1][i].empty() ){ + // d_status = 6; + // return getNextTerm( s, depth ); + //} + s->d_tg_gdepth++; + } + d_status++; + d_status_num = -1; + return getNextTerm( s, depth ); + }else{ + //clean up + Assert( d_children.empty() ); + Trace("sg-gen-tg-debug2") << "...remove from context " << this << std::endl; + s->changeContext( false ); + Assert( d_id==s->d_tg_id ); + return false; + } +} + +void TermGenerator::resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ) { + d_match_status = 0; + d_match_status_child_num = 0; + d_match_children.clear(); + d_match_children_end.clear(); + d_match_mode = mode; + //if this term generalizes, it must generalize a non-ground term + //if( (d_match_mode & ( 1 << 2 ))!=0 && s->isGroundEqc( eqc ) && d_status==5 ){ + // d_match_status = -1; + //} +} + +bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) { + if( d_match_status<0 ){ + return false; + } + if( Trace.isOn("sg-gen-tg-match") ){ + Trace("sg-gen-tg-match") << "Matching "; + debugPrint( s, "sg-gen-tg-match", "sg-gen-tg-match" ); + Trace("sg-gen-tg-match") << " with eqc e" << s->d_cg->d_em[eqc] << "..." << std::endl; + Trace("sg-gen-tg-match") << " mstatus = " << d_match_status; + if( d_status==5 ){ + TNode f = s->getTgFunc( d_typ, d_status_num ); + Trace("sg-gen-tg-debug2") << ", f = " << f; + Trace("sg-gen-tg-debug2") << ", #args = " << s->d_func_args[f].size(); + Trace("sg-gen-tg-debug2") << ", mchildNum = " << d_match_status_child_num; + Trace("sg-gen-tg-debug2") << ", #mchildren = " << d_match_children.size(); + } + Trace("sg-gen-tg-debug2") << ", current substitution : {"; + for( std::map< TypeNode, std::map< unsigned, TNode > >::iterator itt = subs.begin(); itt != subs.end(); ++itt ){ + for( std::map< unsigned, TNode >::iterator it = itt->second.begin(); it != itt->second.end(); ++it ){ + Trace("sg-gen-tg-debug2") << " " << it->first << " -> e" << s->d_cg->d_em[it->second]; + } + } + Trace("sg-gen-tg-debug2") << " } " << std::endl; + } + if( d_status==1 ){ + //a variable + if( d_match_status==0 ){ + d_match_status++; + if( (d_match_mode & ( 1 << 1 ))!=0 ){ + //only ground terms + if( !s->isGroundEqc( eqc ) ){ + return false; + } + }else if( (d_match_mode & ( 1 << 2 ))!=0 ){ + //only non-ground terms + //if( s->isGroundEqc( eqc ) ){ + // return false; + //} + } + //store the match : restricted if match_mode.0 = 1 + if( (d_match_mode & ( 1 << 0 ))!=0 ){ + std::map< TNode, bool >::iterator it = rev_subs.find( eqc ); + if( it==rev_subs.end() ){ + rev_subs[eqc] = true; + }else{ + return false; + } + } + Assert( subs[d_typ].find( d_status_num )==subs[d_typ].end() ); + subs[d_typ][d_status_num] = eqc; + return true; + }else{ + //clean up + subs[d_typ].erase( d_status_num ); + if( (d_match_mode & ( 1 << 0 ))!=0 ){ + rev_subs.erase( eqc ); + } + return false; + } + }else if( d_status==2 ){ + if( d_match_status==0 ){ + d_match_status++; + Assert( d_status_num<(int)s->getNumTgVars( d_typ ) ); + std::map< unsigned, TNode >::iterator it = subs[d_typ].find( d_status_num ); + Assert( it!=subs[d_typ].end() ); + return it->second==eqc; + }else{ + return false; + } + }else if( d_status==5 ){ + //Assert( d_match_children.size()<=d_children.size() ); + //enumerating over f-applications in eqc + if( d_match_status_child_num<0 ){ + return false; + }else if( d_match_status==0 ){ + //set up next binding + if( d_match_status_child_num==(int)d_match_children.size() ){ + if( d_match_status_child_num==0 ){ + //initial binding + TNode f = s->getTgFunc( d_typ, d_status_num ); + std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc ); + if( it!=s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.end() ){ + d_match_children.push_back( it->second.d_data.begin() ); + d_match_children_end.push_back( it->second.d_data.end() ); + }else{ + d_match_status++; + d_match_status_child_num--; + return getNextMatch( s, eqc, subs, rev_subs ); + } + }else{ + d_match_children.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.begin() ); + d_match_children_end.push_back( d_match_children[d_match_status_child_num-1]->second.d_data.end() ); + } + } + d_match_status++; + Assert( d_match_status_child_num+1==(int)d_match_children.size() ); + if( d_match_children[d_match_status_child_num]==d_match_children_end[d_match_status_child_num] ){ + //no more arguments to bind + d_match_children.pop_back(); + d_match_children_end.pop_back(); + d_match_status_child_num--; + return getNextMatch( s, eqc, subs, rev_subs ); + }else{ + if( d_match_status_child_num==(int)d_children.size() ){ + //successfully matched all children + d_match_children.pop_back(); + d_match_children_end.pop_back(); + d_match_status_child_num--; + return true;//return d_match_children[d_match_status]!=d_match_children_end[d_match_status]; + }else{ + //do next binding + s->d_tg_alloc[d_children[d_match_status_child_num]].resetMatching( s, d_match_children[d_match_status_child_num]->first, d_match_mode ); + return getNextMatch( s, eqc, subs, rev_subs ); + } + } + }else{ + Assert( d_match_status==1 ); + Assert( d_match_status_child_num+1==(int)d_match_children.size() ); + Assert( d_match_children[d_match_status_child_num]!=d_match_children_end[d_match_status_child_num] ); + d_match_status--; + if( s->d_tg_alloc[d_children[d_match_status_child_num]].getNextMatch( s, d_match_children[d_match_status_child_num]->first, subs, rev_subs ) ){ + d_match_status_child_num++; + return getNextMatch( s, eqc, subs, rev_subs ); + }else{ + //iterate + d_match_children[d_match_status_child_num]++; + return getNextMatch( s, eqc, subs, rev_subs ); + } + } + } + Assert( false ); + return false; +} + +unsigned TermGenerator::getDepth( TermGenEnv * s ) { + if( d_status==5 ){ + unsigned maxd = 0; + for( unsigned i=0; id_tg_alloc[d_children[i]].getDepth( s ); + if( d>maxd ){ + maxd = d; + } + } + return 1+maxd; + }else{ + return 0; + } +} + +unsigned TermGenerator::calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ) { + if( d_status==5 ){ + unsigned sum = 1; + for( unsigned i=0; id_tg_alloc[d_children[i]].calculateGeneralizationDepth( s, fvs ); + } + return sum; + }else{ + Assert( d_status==2 || d_status==1 ); + std::map< TypeNode, std::vector< int > >::iterator it = fvs.find( d_typ ); + if( it!=fvs.end() ){ + if( std::find( it->second.begin(), it->second.end(), d_status_num )!=it->second.end() ){ + return 1; + } + } + fvs[d_typ].push_back( d_status_num ); + return 0; + } +} + +unsigned TermGenerator::getGeneralizationDepth( TermGenEnv * s ) { + //if( s->d_gen_relevant_terms ){ + // return s->d_tg_gdepth; + //}else{ + std::map< TypeNode, std::vector< int > > fvs; + return calculateGeneralizationDepth( s, fvs ); + //} +} + +Node TermGenerator::getTerm( TermGenEnv * s ) { + if( d_status==1 || d_status==2 ){ + Assert( !d_typ.isNull() ); + return s->getFreeVar( d_typ, d_status_num ); + }else if( d_status==5 ){ + Node f = s->getTgFunc( d_typ, d_status_num ); + if( d_children.size()==s->d_func_args[f].size() ){ + std::vector< Node > children; + if( s->d_tg_func_param[f] ){ + children.push_back( f ); + } + for( unsigned i=0; id_tg_alloc[d_children[i]].getTerm( s ); + if( nc.isNull() ){ + return Node::null(); + }else{ + //Assert( nc.getType()==s->d_func_args[f][i] ); + children.push_back( nc ); + } + } + return NodeManager::currentNM()->mkNode( s->d_func_kind[f], children ); + } + }else{ + Assert( false ); + } + return Node::null(); +} + +void TermGenerator::debugPrint( TermGenEnv * s, const char * c, const char * cd ) { + Trace(cd) << "[*" << d_id << "," << d_status << "]:"; + if( d_status==1 || d_status==2 ){ + Trace(c) << s->getFreeVar( d_typ, d_status_num ); + }else if( d_status==5 ){ + TNode f = s->getTgFunc( d_typ, d_status_num ); + Trace(c) << "(" << f; + for( unsigned i=0; id_tg_alloc[d_children[i]].debugPrint( s, c, cd ); + } + if( d_children.size()d_func_args[f].size() ){ + Trace(c) << " ..."; + } + Trace(c) << ")"; + }else{ + Trace(c) << "???"; + } +} + +void TermGenEnv::collectSignatureInformation() { + d_typ_tg_funcs.clear(); + d_funcs.clear(); + d_func_kind.clear(); + d_func_args.clear(); + TypeNode tnull; + for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){ + if( !getTermDatabase()->d_op_map[it->first].empty() ){ + Node nn = getTermDatabase()->d_op_map[it->first][0]; + if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){ + bool do_enum = true; + //check if we have enumerated ground terms + if( nn.getKind()==APPLY_UF ){ + if( !d_cg->hasEnumeratedUf( nn ) ){ + do_enum = false; + } + } + if( do_enum ){ + d_funcs.push_back( it->first ); + for( unsigned i=0; ifirst].push_back( nn[i].getType() ); + } + d_func_kind[it->first] = nn.getKind(); + d_typ_tg_funcs[tnull].push_back( it->first ); + d_typ_tg_funcs[nn.getType()].push_back( it->first ); + d_tg_func_param[it->first] = ( nn.getMetaKind() == kind::metakind::PARAMETERIZED ); + Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl; + getTermDatabase()->computeUfEqcTerms( it->first ); + } + } + } + } + //shuffle functions + for( std::map< TypeNode, std::vector< TNode > >::iterator it = d_typ_tg_funcs.begin(); it != d_typ_tg_funcs.end(); ++it ){ + std::random_shuffle( it->second.begin(), it->second.end() ); + if( it->first.isNull() ){ + Trace("sg-gen-tg-debug") << "In this order : "; + for( unsigned i=0; isecond.size(); i++ ){ + Trace("sg-gen-tg-debug") << it->second[i] << " "; + } + Trace("sg-gen-tg-debug") << std::endl; + } + } +} + +void TermGenEnv::reset( unsigned depth, bool genRelevant, TypeNode tn ) { + Assert( d_tg_alloc.empty() ); + d_tg_alloc.clear(); + + if( genRelevant ){ + for( unsigned i=0; i<2; i++ ){ + d_ccand_eqc[i].clear(); + d_ccand_eqc[i].push_back( d_relevant_eqc[i] ); + } + } + + d_tg_id = 0; + d_tg_gdepth = 0; + d_tg_gdepth_limit = depth; + d_gen_relevant_terms = genRelevant; + d_tg_alloc[0].reset( this, tn ); +} + +bool TermGenEnv::getNextTerm() { + if( d_tg_alloc[0].getNextTerm( this, d_tg_gdepth_limit ) ){ + Assert( (int)d_tg_alloc[0].getGeneralizationDepth( this )<=d_tg_gdepth_limit ); + if( (int)d_tg_alloc[0].getGeneralizationDepth( this )!=d_tg_gdepth_limit ){ + return getNextTerm(); + }else{ + return true; + } + }else{ + return false; + } +} + +//reset matching +void TermGenEnv::resetMatching( TNode eqc, unsigned mode ) { + d_tg_alloc[0].resetMatching( this, eqc, mode ); +} + +//get next match +bool TermGenEnv::getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ) { + return d_tg_alloc[0].getNextMatch( this, eqc, subs, rev_subs ); +} + +//get term +Node TermGenEnv::getTerm() { + return d_tg_alloc[0].getTerm( this ); +} + +void TermGenEnv::debugPrint( const char * c, const char * cd ) { + d_tg_alloc[0].debugPrint( this, c, cd ); +} + +unsigned TermGenEnv::getNumTgVars( TypeNode tn ) { + return d_var_id[tn]; +} + +bool TermGenEnv::allowVar( TypeNode tn ) { + std::map< TypeNode, unsigned >::iterator it = d_var_limit.find( tn ); + if( it==d_var_limit.end() ){ + return true; + }else{ + return d_var_id[tn]second; + } +} + +void TermGenEnv::addVar( TypeNode tn ) { + d_var_id[tn]++; +} + +void TermGenEnv::removeVar( TypeNode tn ) { + d_var_id[tn]--; + //d_var_eq_tg.pop_back(); + //d_var_tg.pop_back(); +} + +unsigned TermGenEnv::getNumTgFuncs( TypeNode tn ) { + return d_typ_tg_funcs[tn].size(); +} + +TNode TermGenEnv::getTgFunc( TypeNode tn, unsigned i ) { + return d_typ_tg_funcs[tn][i]; +} + +Node TermGenEnv::getFreeVar( TypeNode tn, unsigned i ) { + return d_cg->getFreeVar( tn, i ); +} + +bool TermGenEnv::considerCurrentTerm() { + Assert( !d_tg_alloc.empty() ); + + //if generalization depth is too large, don't consider it + unsigned i = d_tg_alloc.size(); + Trace("sg-gen-tg-debug") << "Consider term "; + d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" ); + Trace("sg-gen-tg-debug") << "? curr term size = " << d_tg_alloc.size() << ", last status = " << d_tg_alloc[i-1].d_status; + Trace("sg-gen-tg-debug") << std::endl; + + if( d_tg_gdepth_limit>=0 && d_tg_alloc[0].getGeneralizationDepth( this )>(unsigned)d_tg_gdepth_limit ){ + Trace("sg-gen-consider-term") << "-> generalization depth of "; + d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-tg-debug" ); + Trace("sg-gen-consider-term") << " is too high " << d_tg_gdepth << " " << d_tg_alloc[0].getGeneralizationDepth( this ) << ", do not consider." << std::endl; + return false; + } + + //----optimizations + /* + if( d_tg_alloc[i-1].d_status==1 ){ + }else if( d_tg_alloc[i-1].d_status==2 ){ + }else if( d_tg_alloc[i-1].d_status==5 ){ + }else{ + Trace("sg-gen-tg-debug") << "Bad tg: " << &d_tg_alloc[i-1] << std::endl; + Assert( false ); + } + */ + //if equated two variables, first check if context-independent TODO + //----end optimizations + + + //check based on which candidate equivalence classes match + if( d_gen_relevant_terms ){ + Trace("sg-gen-tg-debug") << "Filter based on relevant ground EQC"; + Trace("sg-gen-tg-debug") << ", #eqc to try = " << d_ccand_eqc[0][i-1].size() << "/" << d_ccand_eqc[1][i-1].size() << std::endl; + + Assert( d_ccand_eqc[0].size()>=2 ); + Assert( d_ccand_eqc[0].size()==d_ccand_eqc[1].size() ); + Assert( d_ccand_eqc[0].size()==d_tg_id+1 ); + Assert( d_tg_id==d_tg_alloc.size() ); + for( unsigned r=0; r<2; r++ ){ + d_ccand_eqc[r][i].clear(); + } + + //re-check feasibility of EQC + for( unsigned r=0; r<2; r++ ){ + for( unsigned j=0; j > subs; + std::map< TNode, bool > rev_subs; + unsigned mode; + if( r==0 ){ + mode = d_cg->optReqDistinctVarPatterns() ? ( 1 << 0 ) : 0; + mode = mode | (1 << 2 ); + }else{ + mode = 1 << 1; + } + d_tg_alloc[0].resetMatching( this, d_ccand_eqc[r][i-1][j], mode ); + if( d_tg_alloc[0].getNextMatch( this, d_ccand_eqc[r][i-1][j], subs, rev_subs ) ){ + d_ccand_eqc[r][i].push_back( d_ccand_eqc[r][i-1][j] ); + } + } + } + for( unsigned r=0; r<2; r++ ){ + Trace("sg-gen-tg-debug") << "Current eqc of type " << r << " : "; + for( unsigned j=0; jd_em[d_ccand_eqc[r][i][j]] << " "; + } + Trace("sg-gen-tg-debug") << std::endl; + } + if( options::conjectureFilterActiveTerms() && d_ccand_eqc[0][i].empty() ){ + Trace("sg-gen-consider-term") << "Do not consider term of form "; + d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" ); + Trace("sg-gen-consider-term") << " since no relevant EQC matches it." << std::endl; + return false; + } + if( options::conjectureFilterModel() && d_ccand_eqc[1][i].empty() ){ + Trace("sg-gen-consider-term") << "Do not consider term of form "; + d_tg_alloc[0].debugPrint( this, "sg-gen-consider-term", "sg-gen-consider-term-debug" ); + Trace("sg-gen-consider-term") << " since no ground EQC matches it." << std::endl; + return false; + } + } + Trace("sg-gen-tg-debug") << "Will consider term "; + d_tg_alloc[0].debugPrint( this, "sg-gen-tg-debug", "sg-gen-tg-debug" ); + Trace("sg-gen-tg-debug") << std::endl; + Trace("sg-gen-consider-term-debug") << std::endl; + return true; +} + +void TermGenEnv::changeContext( bool add ) { + if( add ){ + for( unsigned r=0; r<2; r++ ){ + d_ccand_eqc[r].push_back( std::vector< TNode >() ); + } + d_tg_id++; + }else{ + for( unsigned r=0; r<2; r++ ){ + d_ccand_eqc[r].pop_back(); + } + d_tg_id--; + Assert( d_tg_alloc.find( d_tg_id )!=d_tg_alloc.end() ); + d_tg_alloc.erase( d_tg_id ); + } +} + +bool TermGenEnv::considerCurrentTermCanon( unsigned tg_id ){ + Assert( tg_idconsiderTermCanon( ln, d_gen_relevant_terms ); + } + return true; +} + +bool TermGenEnv::isRelevantFunc( Node f ) { + return std::find( d_funcs.begin(), d_funcs.end(), f )!=d_funcs.end(); +} +TermDb * TermGenEnv::getTermDatabase() { + return d_cg->getTermDatabase(); +} +Node TermGenEnv::getGroundEqc( TNode r ) { + return d_cg->getGroundEqc( r ); +} +bool TermGenEnv::isGroundEqc( TNode r ){ + return d_cg->isGroundEqc( r ); +} +bool TermGenEnv::isGroundTerm( TNode n ){ + return d_cg->isGroundTerm( n ); +} + + +void SubstitutionIndex::addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i ) { + if( i==vars.size() ){ + d_var = eqc; + }else{ + Assert( d_var.isNull() || d_var==vars[i] ); + d_var = vars[i]; + d_children[terms[i]].addSubstitution( eqc, vars, terms, i+1 ); + } +} + +bool SubstitutionIndex::notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i ) { + if( i==numVars ){ + Assert( d_children.empty() ); + return s->notifySubstitution( d_var, subs, rhs ); + }else{ + Assert( i==0 || !d_children.empty() ); + for( std::map< TNode, SubstitutionIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ + Trace("sg-cconj-debug2") << "Try " << d_var << " -> " << it->first << " (" << i << "/" << numVars << ")" << std::endl; + subs[d_var] = it->first; + if( !it->second.notifySubstitutions( s, subs, rhs, numVars, i+1 ) ){ + return false; + } + } + return true; + } +} + + +void TheoremIndex::addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){ + if( lhs_v.empty() ){ + if( std::find( d_terms.begin(), d_terms.end(), rhs )==d_terms.end() ){ + d_terms.push_back( rhs ); + } + }else{ + unsigned index = lhs_v.size()-1; + if( lhs_arg[index]==lhs_v[index].getNumChildren() ){ + lhs_v.pop_back(); + lhs_arg.pop_back(); + addTheorem( lhs_v, lhs_arg, rhs ); + }else{ + lhs_arg[index]++; + addTheoremNode( lhs_v[index][lhs_arg[index]-1], lhs_v, lhs_arg, rhs ); + } + } +} + +void TheoremIndex::addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ){ + Trace("thm-db-debug") << "Adding conjecture for subterm " << curr << "..." << std::endl; + if( curr.hasOperator() ){ + lhs_v.push_back( curr ); + lhs_arg.push_back( 0 ); + d_children[curr.getOperator()].addTheorem( lhs_v, lhs_arg, rhs ); + }else{ + Assert( curr.getKind()==kind::BOUND_VARIABLE ); + TypeNode tn = curr.getType(); + Assert( d_var[tn].isNull() || d_var[tn]==curr ); + d_var[tn] = curr; + d_children[curr].addTheorem( lhs_v, lhs_arg, rhs ); + } +} + +void TheoremIndex::getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg, + std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, + std::vector< Node >& terms ) { + Trace("thm-db-debug") << "Get equivalent terms " << n_v.size() << " " << n_arg.size() << std::endl; + if( n_v.empty() ){ + Trace("thm-db-debug") << "Number of terms : " << d_terms.size() << std::endl; + //apply substutitions to RHS's + for( unsigned i=0; i& n_v, std::vector< unsigned >& n_arg, + std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, + std::vector< Node >& terms ) { + Trace("thm-db-debug") << "Get equivalent based on subterm " << curr << "..." << std::endl; + if( curr.hasOperator() ){ + Trace("thm-db-debug") << "Check based on operator..." << std::endl; + std::map< TNode, TheoremIndex >::iterator it = d_children.find( curr.getOperator() ); + if( it!=d_children.end() ){ + n_v.push_back( curr ); + n_arg.push_back( 0 ); + it->second.getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms ); + } + Trace("thm-db-debug") << "...done check based on operator" << std::endl; + } + TypeNode tn = curr.getType(); + std::map< TypeNode, TNode >::iterator itt = d_var.find( tn ); + if( itt!=d_var.end() ){ + Trace("thm-db-debug") << "Check for substitution with " << itt->second << "..." << std::endl; + Assert( curr.getType()==itt->second.getType() ); + //add to substitution if possible + bool success = false; + std::map< TNode, TNode >::iterator it = smap.find( itt->second ); + if( it==smap.end() ){ + smap[itt->second] = curr; + vars.push_back( itt->second ); + subs.push_back( curr ); + success = true; + }else if( it->second==curr ){ + success = true; + }else{ + //also check modulo equality (in universal equality engine) + } + Trace("thm-db-debug") << "...check for substitution with " << itt->second << ", success = " << success << "." << std::endl; + if( success ){ + d_children[itt->second].getEquivalentTerms( n_v, n_arg, smap, vars, subs, terms ); + } + } +} + +void TheoremIndex::debugPrint( const char * c, unsigned ind ) { + for( std::map< TNode, TheoremIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){ + for( unsigned i=0; ifirst << std::endl; + it->second.debugPrint( c, ind+1 ); + } + if( !d_terms.empty() ){ + for( unsigned i=0; i d_child; - std::vector< TNode > d_ops; - std::vector< TNode > d_op_terms; - void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 ); - Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ); - void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ); -}; - -class PatternTypIndex -{ -public: - std::vector< TNode > d_terms; - std::map< TypeNode, std::map< unsigned, PatternTypIndex > > d_children; - void clear() { - d_terms.clear(); - d_children.clear(); - } -}; - -class SubstitutionIndex -{ -public: - //current variable, or ground EQC if d_children.empty() - TNode d_var; - std::map< TNode, SubstitutionIndex > d_children; - //add substitution - void addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i = 0 ); - //notify substitutions - bool notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i = 0 ); -}; - -class TermGenEnv; - -class TermGenerator -{ -private: - unsigned calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ); -public: - TermGenerator(){} - TypeNode d_typ; - unsigned d_id; - //1 : consider as unique variable - //2 : consider equal to another variable - //5 : consider a function application - unsigned d_status; - int d_status_num; - //for function applications: the number of children you have built - int d_status_child_num; - //children (pointers to TermGenerators) - std::vector< unsigned > d_children; - - //match status - int d_match_status; - int d_match_status_child_num; - //match mode bits - //0 : different variables must have different matches - //1 : variables must map to ground terms - //2 : variables must map to non-ground terms - unsigned d_match_mode; - //children - std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children; - std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children_end; - - void reset( TermGenEnv * s, TypeNode tn ); - bool getNextTerm( TermGenEnv * s, unsigned depth ); - void resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ); - bool getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ); - - unsigned getDepth( TermGenEnv * s ); - unsigned getGeneralizationDepth( TermGenEnv * s ); - Node getTerm( TermGenEnv * s ); - - void debugPrint( TermGenEnv * s, const char * c, const char * cd ); -}; - - -class TermGenEnv -{ -public: - //collect signature information - void collectSignatureInformation(); - //reset function - void reset( unsigned gdepth, bool genRelevant, TypeNode tgen ); - //get next term - bool getNextTerm(); - //reset matching - void resetMatching( TNode eqc, unsigned mode ); - //get next match - bool getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ); - //get term - Node getTerm(); - //debug print - void debugPrint( const char * c, const char * cd ); - - //conjecture generation - ConjectureGenerator * d_cg; - //the current number of enumerated variables per type - std::map< TypeNode, unsigned > d_var_id; - //the limit of number of variables per type to enumerate - std::map< TypeNode, unsigned > d_var_limit; - //the functions we can currently generate - std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs; - // whether functions must add operators - std::map< TNode, bool > d_tg_func_param; - //the equivalence classes (if applicable) that match the currently generated term - bool d_gen_relevant_terms; - //relevant equivalence classes - std::vector< TNode > d_relevant_eqc[2]; - //candidate equivalence classes - std::vector< std::vector< TNode > > d_ccand_eqc[2]; - //the term generation objects - unsigned d_tg_id; - std::map< unsigned, TermGenerator > d_tg_alloc; - unsigned d_tg_gdepth; - int d_tg_gdepth_limit; - - //all functions - std::vector< TNode > d_funcs; - //function to kind map - std::map< TNode, Kind > d_func_kind; - //type of each argument of the function - std::map< TNode, std::vector< TypeNode > > d_func_args; - - //access functions - unsigned getNumTgVars( TypeNode tn ); - bool allowVar( TypeNode tn ); - void addVar( TypeNode tn ); - void removeVar( TypeNode tn ); - unsigned getNumTgFuncs( TypeNode tn ); - TNode getTgFunc( TypeNode tn, unsigned i ); - Node getFreeVar( TypeNode tn, unsigned i ); - bool considerCurrentTerm(); - bool considerCurrentTermCanon( unsigned tg_id ); - void changeContext( bool add ); - bool isRelevantFunc( Node f ); - //carry - TermDb * getTermDatabase(); - Node getGroundEqc( TNode r ); - bool isGroundEqc( TNode r ); - bool isGroundTerm( TNode n ); -}; - - - -class TheoremIndex -{ -private: - void addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ); - void addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ); - void getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg, - std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, - std::vector< Node >& terms ); - void getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg, - std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, - std::vector< Node >& terms ); -public: - std::map< TypeNode, TNode > d_var; - std::map< TNode, TheoremIndex > d_children; - std::vector< Node > d_terms; - - void addTheorem( TNode lhs, TNode rhs ) { - std::vector< TNode > v; - std::vector< unsigned > a; - addTheoremNode( lhs, v, a, rhs ); - } - void getEquivalentTerms( TNode n, std::vector< Node >& terms ) { - std::vector< TNode > nv; - std::vector< unsigned > na; - std::map< TNode, TNode > smap; - std::vector< TNode > vars; - std::vector< TNode > subs; - getEquivalentTermsNode( n, nv, na, smap, vars, subs, terms ); - } - void clear(){ - d_var.clear(); - d_children.clear(); - d_terms.clear(); - } - void debugPrint( const char * c, unsigned ind = 0 ); -}; - - - -class ConjectureGenerator : public QuantifiersModule -{ - friend class OpArgIndex; - friend class PatGen; - friend class PatternGenEqc; - friend class PatternGen; - friend class SubsEqcIndex; - friend class TermGenerator; - friend class TermGenEnv; - typedef context::CDChunkList NodeList; - typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap; - typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; -//this class maintains a congruence closure for *universal* facts -private: - //notification class for equality engine - class NotifyClass : public eq::EqualityEngineNotify { - ConjectureGenerator& d_sg; - public: - NotifyClass(ConjectureGenerator& sg): d_sg(sg) {} - bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; } - bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; } - bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; } - void eqNotifyConstantTermMerge(TNode t1, TNode t2) { } - void eqNotifyNewClass(TNode t) { d_sg.eqNotifyNewClass(t); } - void eqNotifyPreMerge(TNode t1, TNode t2) { d_sg.eqNotifyPreMerge(t1, t2); } - void eqNotifyPostMerge(TNode t1, TNode t2) { d_sg.eqNotifyPostMerge(t1, t2); } - void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {d_sg.eqNotifyDisequal(t1, t2, reason); } - };/* class ConjectureGenerator::NotifyClass */ - /** The notify class */ - NotifyClass d_notify; - class EqcInfo{ - public: - EqcInfo( context::Context* c ); - //representative - context::CDO< Node > d_rep; - }; - /** get or make eqc info */ - EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false ); - /** (universal) equaltity engine */ - eq::EqualityEngine d_uequalityEngine; - /** pending adds */ - std::vector< Node > d_upendingAdds; - /** relevant terms */ - std::map< Node, bool > d_urelevant_terms; - /** information necessary for equivalence classes */ - std::map< Node, EqcInfo* > d_eqc_info; - /** called when a new equivalance class is created */ - void eqNotifyNewClass(TNode t); - /** called when two equivalance classes will merge */ - void eqNotifyPreMerge(TNode t1, TNode t2); - /** called when two equivalance classes have merged */ - void eqNotifyPostMerge(TNode t1, TNode t2); - /** called when two equivalence classes are made disequal */ - void eqNotifyDisequal(TNode t1, TNode t2, TNode reason); - /** are universal equal */ - bool areUniversalEqual( TNode n1, TNode n2 ); - /** are universal disequal */ - bool areUniversalDisequal( TNode n1, TNode n2 ); - /** get universal representative */ - TNode getUniversalRepresentative( TNode n, bool add = false ); - /** set relevant */ - void setUniversalRelevant( TNode n ); - /** ordering for universal terms */ - bool isUniversalLessThan( TNode rt1, TNode rt2 ); - - /** the nodes we have reported as canonical representative */ - std::vector< TNode > d_ue_canon; - /** is reported canon */ - bool isReportedCanon( TNode n ); - /** mark that term has been reported as canonical rep */ - void markReportedCanon( TNode n ); - -private: //information regarding the conjectures - /** list of all conjectures */ - std::vector< Node > d_conjectures; - /** list of all waiting conjectures */ - std::vector< Node > d_waiting_conjectures_lhs; - std::vector< Node > d_waiting_conjectures_rhs; - std::vector< int > d_waiting_conjectures_score; - /** map of currently considered equality conjectures */ - std::map< Node, std::vector< Node > > d_waiting_conjectures; - /** map of equality conjectures */ - std::map< Node, std::vector< Node > > d_eq_conjectures; - /** currently existing conjectures in equality engine */ - BoolMap d_ee_conjectures; - /** conjecture index */ - TheoremIndex d_thm_index; -private: //free variable list - //free variables - std::map< TypeNode, std::vector< Node > > d_free_var; - //map from free variable to FV# - std::map< TNode, unsigned > d_free_var_num; - // get canonical free variable #i of type tn - Node getFreeVar( TypeNode tn, unsigned i ); - // get canonical term, return null if it contains a term apart from handled signature - Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ); -private: //information regarding the terms - //relevant patterns (the LHS's) - std::map< TypeNode, std::vector< Node > > d_rel_patterns; - //total number of unique variables - std::map< TNode, unsigned > d_rel_pattern_var_sum; - //by types - PatternTypIndex d_rel_pattern_typ_index; - // substitution to ground EQC index - std::map< TNode, SubstitutionIndex > d_rel_pattern_subs_index; - //patterns (the RHS's) - std::map< TypeNode, std::vector< Node > > d_patterns; - //patterns to # variables per type - std::map< TNode, std::map< TypeNode, unsigned > > d_pattern_var_id; - // # duplicated variables - std::map< TNode, unsigned > d_pattern_var_duplicate; - // is normal pattern? (variables allocated in canonical way left to right) - std::map< TNode, int > d_pattern_is_normal; - std::map< TNode, int > d_pattern_is_relevant; - // patterns to a count of # operators (variables and functions) - std::map< TNode, std::map< TNode, unsigned > > d_pattern_fun_id; - // term size - std::map< TNode, unsigned > d_pattern_fun_sum; - // collect functions - unsigned collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs, - std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ); - // add pattern - void registerPattern( Node pat, TypeNode tpat ); -private: //for debugging - std::map< TNode, unsigned > d_em; - unsigned d_conj_count; -public: - //term generation environment - TermGenEnv d_tge; - //consider term canon - bool considerTermCanon( Node ln, bool genRelevant ); -public: //for generalization - //generalizations - bool isGeneralization( TNode patg, TNode pat ) { - std::map< TNode, TNode > subs; - return isGeneralization( patg, pat, subs ); - } - bool isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ); - // get generalization depth - int calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv ); -private: - //predicate for type - std::map< TypeNode, Node > d_typ_pred; - //get predicate for type - Node getPredicateForType( TypeNode tn ); - // - void getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ); - // - void getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms ); - // uf operators enumerated - std::map< Node, bool > d_uf_enum; -public: //for property enumeration - //process this candidate conjecture - void processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ); - //whether it should be considered, negative : no, positive returns score - int considerCandidateConjecture( TNode lhs, TNode rhs ); - //notified of a substitution - bool notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ); - //confirmation count - unsigned d_subs_confirmCount; - //individual witnesses (for range) - std::vector< TNode > d_subs_confirmWitnessRange; - //individual witnesses (for domain) - std::map< TNode, std::vector< TNode > > d_subs_confirmWitnessDomain; - //number of ground substitutions whose equality is unknown - unsigned d_subs_unkCount; -private: //information about ground equivalence classes - TNode d_bool_eqc[2]; - std::map< TNode, Node > d_ground_eqc_map; - std::vector< TNode > d_ground_terms; - //operator independent term index - std::map< TNode, OpArgIndex > d_op_arg_index; - //is handled term - bool isHandledTerm( TNode n ); - Node getGroundEqc( TNode r ); - bool isGroundEqc( TNode r ); - bool isGroundTerm( TNode n ); - //has enumerated UF - bool hasEnumeratedUf( Node n ); - // count of full effort checks - unsigned d_fullEffortCount; - // has added lemma - bool d_hasAddedLemma; - //flush the waiting conjectures - unsigned flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ); -public: - ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ); - ~ConjectureGenerator() throw() {} - /* needs check */ - bool needsCheck( Theory::Effort e ); - /* reset at a round */ - void reset_round( Theory::Effort e ); - /* Call during quantifier engine's check */ - void check( Theory::Effort e, unsigned quant_e ); - /* Called for new quantifiers */ - void registerQuantifier( Node q ); - void assertNode( Node n ); - /** Identify this module (for debugging, dynamic configuration, etc..) */ - std::string identify() const { return "ConjectureGenerator"; } -//options -private: - bool optReqDistinctVarPatterns(); - bool optFilterUnknown(); - int optFilterScoreThreshold(); - unsigned optFullCheckFrequency(); - unsigned optFullCheckConjectures(); - - bool optStatsOnly(); -}; - - -} -} -} - -#endif +/********************* */ +/*! \file conjecture_generator.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2014 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief conjecture generator class + **/ + +#include "cvc4_private.h" + +#ifndef CONJECTURE_GENERATOR_H +#define CONJECTURE_GENERATOR_H + +#include "context/cdhashmap.h" +#include "context/cdchunk_list.h" +#include "theory/quantifiers_engine.h" +#include "theory/type_enumerator.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class TermArgTrie; + +//algorithm for computing candidate subgoals + +class ConjectureGenerator; + +// operator independent index of arguments for an EQC +class OpArgIndex +{ +public: + std::map< TNode, OpArgIndex > d_child; + std::vector< TNode > d_ops; + std::vector< TNode > d_op_terms; + void addTerm( ConjectureGenerator * s, TNode n, unsigned index = 0 ); + Node getGroundTerm( ConjectureGenerator * s, std::vector< TNode >& args ); + void getGroundTerms( ConjectureGenerator * s, std::vector< TNode >& terms ); +}; + +class PatternTypIndex +{ +public: + std::vector< TNode > d_terms; + std::map< TypeNode, std::map< unsigned, PatternTypIndex > > d_children; + void clear() { + d_terms.clear(); + d_children.clear(); + } +}; + +class SubstitutionIndex +{ +public: + //current variable, or ground EQC if d_children.empty() + TNode d_var; + std::map< TNode, SubstitutionIndex > d_children; + //add substitution + void addSubstitution( TNode eqc, std::vector< TNode >& vars, std::vector< TNode >& terms, unsigned i = 0 ); + //notify substitutions + bool notifySubstitutions( ConjectureGenerator * s, std::map< TNode, TNode >& subs, TNode rhs, unsigned numVars, unsigned i = 0 ); +}; + +class TermGenEnv; + +class TermGenerator +{ +private: + unsigned calculateGeneralizationDepth( TermGenEnv * s, std::map< TypeNode, std::vector< int > >& fvs ); +public: + TermGenerator(){} + TypeNode d_typ; + unsigned d_id; + //1 : consider as unique variable + //2 : consider equal to another variable + //5 : consider a function application + unsigned d_status; + int d_status_num; + //for function applications: the number of children you have built + int d_status_child_num; + //children (pointers to TermGenerators) + std::vector< unsigned > d_children; + + //match status + int d_match_status; + int d_match_status_child_num; + //match mode bits + //0 : different variables must have different matches + //1 : variables must map to ground terms + //2 : variables must map to non-ground terms + unsigned d_match_mode; + //children + std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children; + std::vector< std::map< TNode, TermArgTrie >::iterator > d_match_children_end; + + void reset( TermGenEnv * s, TypeNode tn ); + bool getNextTerm( TermGenEnv * s, unsigned depth ); + void resetMatching( TermGenEnv * s, TNode eqc, unsigned mode ); + bool getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ); + + unsigned getDepth( TermGenEnv * s ); + unsigned getGeneralizationDepth( TermGenEnv * s ); + Node getTerm( TermGenEnv * s ); + + void debugPrint( TermGenEnv * s, const char * c, const char * cd ); +}; + + +class TermGenEnv +{ +public: + //collect signature information + void collectSignatureInformation(); + //reset function + void reset( unsigned gdepth, bool genRelevant, TypeNode tgen ); + //get next term + bool getNextTerm(); + //reset matching + void resetMatching( TNode eqc, unsigned mode ); + //get next match + bool getNextMatch( TNode eqc, std::map< TypeNode, std::map< unsigned, TNode > >& subs, std::map< TNode, bool >& rev_subs ); + //get term + Node getTerm(); + //debug print + void debugPrint( const char * c, const char * cd ); + + //conjecture generation + ConjectureGenerator * d_cg; + //the current number of enumerated variables per type + std::map< TypeNode, unsigned > d_var_id; + //the limit of number of variables per type to enumerate + std::map< TypeNode, unsigned > d_var_limit; + //the functions we can currently generate + std::map< TypeNode, std::vector< TNode > > d_typ_tg_funcs; + // whether functions must add operators + std::map< TNode, bool > d_tg_func_param; + //the equivalence classes (if applicable) that match the currently generated term + bool d_gen_relevant_terms; + //relevant equivalence classes + std::vector< TNode > d_relevant_eqc[2]; + //candidate equivalence classes + std::vector< std::vector< TNode > > d_ccand_eqc[2]; + //the term generation objects + unsigned d_tg_id; + std::map< unsigned, TermGenerator > d_tg_alloc; + unsigned d_tg_gdepth; + int d_tg_gdepth_limit; + + //all functions + std::vector< TNode > d_funcs; + //function to kind map + std::map< TNode, Kind > d_func_kind; + //type of each argument of the function + std::map< TNode, std::vector< TypeNode > > d_func_args; + + //access functions + unsigned getNumTgVars( TypeNode tn ); + bool allowVar( TypeNode tn ); + void addVar( TypeNode tn ); + void removeVar( TypeNode tn ); + unsigned getNumTgFuncs( TypeNode tn ); + TNode getTgFunc( TypeNode tn, unsigned i ); + Node getFreeVar( TypeNode tn, unsigned i ); + bool considerCurrentTerm(); + bool considerCurrentTermCanon( unsigned tg_id ); + void changeContext( bool add ); + bool isRelevantFunc( Node f ); + //carry + TermDb * getTermDatabase(); + Node getGroundEqc( TNode r ); + bool isGroundEqc( TNode r ); + bool isGroundTerm( TNode n ); +}; + + + +class TheoremIndex +{ +private: + void addTheorem( std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ); + void addTheoremNode( TNode curr, std::vector< TNode >& lhs_v, std::vector< unsigned >& lhs_arg, TNode rhs ); + void getEquivalentTerms( std::vector< TNode >& n_v, std::vector< unsigned >& n_arg, + std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, + std::vector< Node >& terms ); + void getEquivalentTermsNode( Node curr, std::vector< TNode >& n_v, std::vector< unsigned >& n_arg, + std::map< TNode, TNode >& smap, std::vector< TNode >& vars, std::vector< TNode >& subs, + std::vector< Node >& terms ); +public: + std::map< TypeNode, TNode > d_var; + std::map< TNode, TheoremIndex > d_children; + std::vector< Node > d_terms; + + void addTheorem( TNode lhs, TNode rhs ) { + std::vector< TNode > v; + std::vector< unsigned > a; + addTheoremNode( lhs, v, a, rhs ); + } + void getEquivalentTerms( TNode n, std::vector< Node >& terms ) { + std::vector< TNode > nv; + std::vector< unsigned > na; + std::map< TNode, TNode > smap; + std::vector< TNode > vars; + std::vector< TNode > subs; + getEquivalentTermsNode( n, nv, na, smap, vars, subs, terms ); + } + void clear(){ + d_var.clear(); + d_children.clear(); + d_terms.clear(); + } + void debugPrint( const char * c, unsigned ind = 0 ); +}; + + + +class ConjectureGenerator : public QuantifiersModule +{ + friend class OpArgIndex; + friend class PatGen; + friend class PatternGenEqc; + friend class PatternGen; + friend class SubsEqcIndex; + friend class TermGenerator; + friend class TermGenEnv; + typedef context::CDChunkList NodeList; + typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap; + typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; +//this class maintains a congruence closure for *universal* facts +private: + //notification class for equality engine + class NotifyClass : public eq::EqualityEngineNotify { + ConjectureGenerator& d_sg; + public: + NotifyClass(ConjectureGenerator& sg): d_sg(sg) {} + bool eqNotifyTriggerEquality(TNode equality, bool value) { return true; } + bool eqNotifyTriggerPredicate(TNode predicate, bool value) { return true; } + bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) { return true; } + void eqNotifyConstantTermMerge(TNode t1, TNode t2) { } + void eqNotifyNewClass(TNode t) { d_sg.eqNotifyNewClass(t); } + void eqNotifyPreMerge(TNode t1, TNode t2) { d_sg.eqNotifyPreMerge(t1, t2); } + void eqNotifyPostMerge(TNode t1, TNode t2) { d_sg.eqNotifyPostMerge(t1, t2); } + void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {d_sg.eqNotifyDisequal(t1, t2, reason); } + };/* class ConjectureGenerator::NotifyClass */ + /** The notify class */ + NotifyClass d_notify; + class EqcInfo{ + public: + EqcInfo( context::Context* c ); + //representative + context::CDO< Node > d_rep; + }; + /** get or make eqc info */ + EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false ); + /** (universal) equaltity engine */ + eq::EqualityEngine d_uequalityEngine; + /** pending adds */ + std::vector< Node > d_upendingAdds; + /** relevant terms */ + std::map< Node, bool > d_urelevant_terms; + /** information necessary for equivalence classes */ + std::map< Node, EqcInfo* > d_eqc_info; + /** called when a new equivalance class is created */ + void eqNotifyNewClass(TNode t); + /** called when two equivalance classes will merge */ + void eqNotifyPreMerge(TNode t1, TNode t2); + /** called when two equivalance classes have merged */ + void eqNotifyPostMerge(TNode t1, TNode t2); + /** called when two equivalence classes are made disequal */ + void eqNotifyDisequal(TNode t1, TNode t2, TNode reason); + /** are universal equal */ + bool areUniversalEqual( TNode n1, TNode n2 ); + /** are universal disequal */ + bool areUniversalDisequal( TNode n1, TNode n2 ); + /** get universal representative */ + TNode getUniversalRepresentative( TNode n, bool add = false ); + /** set relevant */ + void setUniversalRelevant( TNode n ); + /** ordering for universal terms */ + bool isUniversalLessThan( TNode rt1, TNode rt2 ); + + /** the nodes we have reported as canonical representative */ + std::vector< TNode > d_ue_canon; + /** is reported canon */ + bool isReportedCanon( TNode n ); + /** mark that term has been reported as canonical rep */ + void markReportedCanon( TNode n ); + +private: //information regarding the conjectures + /** list of all conjectures */ + std::vector< Node > d_conjectures; + /** list of all waiting conjectures */ + std::vector< Node > d_waiting_conjectures_lhs; + std::vector< Node > d_waiting_conjectures_rhs; + std::vector< int > d_waiting_conjectures_score; + /** map of currently considered equality conjectures */ + std::map< Node, std::vector< Node > > d_waiting_conjectures; + /** map of equality conjectures */ + std::map< Node, std::vector< Node > > d_eq_conjectures; + /** currently existing conjectures in equality engine */ + BoolMap d_ee_conjectures; + /** conjecture index */ + TheoremIndex d_thm_index; +private: //free variable list + //free variables + std::map< TypeNode, std::vector< Node > > d_free_var; + //map from free variable to FV# + std::map< TNode, unsigned > d_free_var_num; + // get canonical free variable #i of type tn + Node getFreeVar( TypeNode tn, unsigned i ); + // get canonical term, return null if it contains a term apart from handled signature + Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs ); +private: //information regarding the terms + //relevant patterns (the LHS's) + std::map< TypeNode, std::vector< Node > > d_rel_patterns; + //total number of unique variables + std::map< TNode, unsigned > d_rel_pattern_var_sum; + //by types + PatternTypIndex d_rel_pattern_typ_index; + // substitution to ground EQC index + std::map< TNode, SubstitutionIndex > d_rel_pattern_subs_index; + //patterns (the RHS's) + std::map< TypeNode, std::vector< Node > > d_patterns; + //patterns to # variables per type + std::map< TNode, std::map< TypeNode, unsigned > > d_pattern_var_id; + // # duplicated variables + std::map< TNode, unsigned > d_pattern_var_duplicate; + // is normal pattern? (variables allocated in canonical way left to right) + std::map< TNode, int > d_pattern_is_normal; + std::map< TNode, int > d_pattern_is_relevant; + // patterns to a count of # operators (variables and functions) + std::map< TNode, std::map< TNode, unsigned > > d_pattern_fun_id; + // term size + std::map< TNode, unsigned > d_pattern_fun_sum; + // collect functions + unsigned collectFunctions( TNode opat, TNode pat, std::map< TNode, unsigned >& funcs, + std::map< TypeNode, unsigned >& mnvn, std::map< TypeNode, unsigned >& mxvn ); + // add pattern + void registerPattern( Node pat, TypeNode tpat ); +private: //for debugging + std::map< TNode, unsigned > d_em; + unsigned d_conj_count; +public: + //term generation environment + TermGenEnv d_tge; + //consider term canon + bool considerTermCanon( Node ln, bool genRelevant ); +public: //for generalization + //generalizations + bool isGeneralization( TNode patg, TNode pat ) { + std::map< TNode, TNode > subs; + return isGeneralization( patg, pat, subs ); + } + bool isGeneralization( TNode patg, TNode pat, std::map< TNode, TNode >& subs ); + // get generalization depth + int calculateGeneralizationDepth( TNode n, std::vector< TNode >& fv ); +private: + //predicate for type + std::map< TypeNode, Node > d_typ_pred; + //get predicate for type + Node getPredicateForType( TypeNode tn ); + // + void getEnumerateUfTerm( Node n, unsigned num, std::vector< Node >& terms ); + // + void getEnumeratePredUfTerm( Node n, unsigned num, std::vector< Node >& terms ); + // uf operators enumerated + std::map< Node, bool > d_uf_enum; +public: //for property enumeration + //process this candidate conjecture + void processCandidateConjecture( TNode lhs, TNode rhs, unsigned lhs_depth, unsigned rhs_depth ); + //whether it should be considered, negative : no, positive returns score + int considerCandidateConjecture( TNode lhs, TNode rhs ); + //notified of a substitution + bool notifySubstitution( TNode glhs, std::map< TNode, TNode >& subs, TNode rhs ); + //confirmation count + unsigned d_subs_confirmCount; + //individual witnesses (for range) + std::vector< TNode > d_subs_confirmWitnessRange; + //individual witnesses (for domain) + std::map< TNode, std::vector< TNode > > d_subs_confirmWitnessDomain; + //number of ground substitutions whose equality is unknown + unsigned d_subs_unkCount; +private: //information about ground equivalence classes + TNode d_bool_eqc[2]; + std::map< TNode, Node > d_ground_eqc_map; + std::vector< TNode > d_ground_terms; + //operator independent term index + std::map< TNode, OpArgIndex > d_op_arg_index; + //is handled term + bool isHandledTerm( TNode n ); + Node getGroundEqc( TNode r ); + bool isGroundEqc( TNode r ); + bool isGroundTerm( TNode n ); + //has enumerated UF + bool hasEnumeratedUf( Node n ); + // count of full effort checks + unsigned d_fullEffortCount; + // has added lemma + bool d_hasAddedLemma; + //flush the waiting conjectures + unsigned flushWaitingConjectures( unsigned& addedLemmas, int ldepth, int rdepth ); +public: + ConjectureGenerator( QuantifiersEngine * qe, context::Context* c ); + ~ConjectureGenerator() throw() {} + /* needs check */ + bool needsCheck( Theory::Effort e ); + /* reset at a round */ + void reset_round( Theory::Effort e ); + /* Call during quantifier engine's check */ + void check( Theory::Effort e, unsigned quant_e ); + /* Called for new quantifiers */ + void registerQuantifier( Node q ); + void assertNode( Node n ); + /** Identify this module (for debugging, dynamic configuration, etc..) */ + std::string identify() const { return "ConjectureGenerator"; } +//options +private: + bool optReqDistinctVarPatterns(); + bool optFilterUnknown(); + int optFilterScoreThreshold(); + unsigned optFullCheckFrequency(); + unsigned optFullCheckConjectures(); + + bool optStatsOnly(); +}; + + +} +} +} + +#endif diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index d465df4c0..18bffe908 100644 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -1,2227 +1,2227 @@ -/********************* */ -/*! \file quant_conflict_find.cpp - ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief quant conflict find class - ** - **/ - -#include - -#include "theory/quantifiers/quant_conflict_find.h" -#include "theory/quantifiers/quant_util.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers/options.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/trigger.h" - -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::theory; -using namespace CVC4::theory::quantifiers; -using namespace std; - -namespace CVC4 { - - - -void QuantInfo::initialize( Node q, Node qn ) { - d_q = q; - for( unsigned i=0; iisValid() ){ - /* - for( unsigned j=0; jsetInvalid(); - break; - } - } - */ - if( d_mg->isValid() ){ - for( unsigned j=q[0].getNumChildren(); jisValid() ){ - Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; - d_mg->setInvalid(); - break; - }else{ - std::vector< int > bvars; - d_var_mg[j]->determineVariableOrder( this, bvars ); - } - } - } - if( d_mg->isValid() ){ - std::vector< int > bvars; - d_mg->determineVariableOrder( this, bvars ); - } - } - }else{ - Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; - } - Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; -} - -void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { - Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; - if( n.getKind()==FORALL ){ - registerNode( n[1], hasPol, pol, true ); - }else{ - if( !MatchGen::isHandledBoolConnective( n ) ){ - if( n.hasBoundVar() ){ - //literals - if( n.getKind()==EQUAL ){ - for( unsigned i=0; id_parent = qcf; - //qcf->d_child[i] = qcfc; - registerNode( n[i], newHasPol, newPol, beneathQuant ); - } - } - } -} - -void QuantInfo::flatten( Node n, bool beneathQuant ) { - Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl; - if( n.hasBoundVar() ){ - if( n.getKind()==BOUND_VARIABLE ){ - d_inMatchConstraint[n] = true; - } - //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){ - if( d_var_num.find( n )==d_var_num.end() ){ - Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; - d_var_num[n] = d_vars.size(); - d_vars.push_back( n ); - d_var_types.push_back( n.getType() ); - d_match.push_back( TNode::null() ); - d_match_term.push_back( TNode::null() ); - if( n.getKind()==ITE ){ - registerNode( n, false, false ); - }else{ - for( unsigned i=0; i >::iterator it = d_var_constraint[r].begin(); - it != d_var_constraint[r].end(); ++it ){ - for( unsigned j=0; jsecond.size(); j++ ){ - Node rr = it->second[j]; - if( !isVar( rr ) ){ - rr = p->getRepresentative( rr ); - } - if( addConstraint( p, it->first, rr, r==0 )==-1 ){ - d_var_constraint[0].clear(); - d_var_constraint[1].clear(); - //quantified formula is actually equivalent to true - Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl; - d_mg->d_children.clear(); - d_mg->d_n = NodeManager::currentNM()->mkConst( true ); - d_mg->d_type = MatchGen::typ_ground; - return; - } - } - } - } - d_mg->reset_round( p ); - for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){ - it->second->reset_round( p ); - } - //now, reset for matching - d_mg->reset( p, false, this ); -} - -int QuantInfo::getCurrentRepVar( int v ) { - if( v!=-1 && !d_match[v].isNull() ){ - int vn = getVarNum( d_match[v] ); - if( vn!=-1 ){ - //int vr = getCurrentRepVar( vn ); - //d_match[v] = d_vars[vr]; - //return vr; - return getCurrentRepVar( vn ); - } - } - return v; -} - -TNode QuantInfo::getCurrentValue( TNode n ) { - int v = getVarNum( n ); - if( v==-1 ){ - return n; - }else{ - if( d_match[v].isNull() ){ - return n; - }else{ - Assert( getVarNum( d_match[v] )!=v ); - return getCurrentValue( d_match[v] ); - } - } -} - -TNode QuantInfo::getCurrentExpValue( TNode n ) { - int v = getVarNum( n ); - if( v==-1 ){ - return n; - }else{ - if( d_match[v].isNull() ){ - return n; - }else{ - Assert( getVarNum( d_match[v] )!=v ); - if( d_match_term[v].isNull() ){ - return getCurrentValue( d_match[v] ); - }else{ - return d_match_term[v]; - } - } - } -} - -bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) { - //check disequalities - std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); - if( itd!=d_curr_var_deq.end() ){ - for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ - Node cv = getCurrentValue( it->first ); - Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl; - if( cv==n ){ - return false; - }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){ - //they must actually be disequal if we are looking for conflicts - if( !p->areDisequal( n, cv ) ){ - //TODO : check for entailed disequal - - return false; - } - } - } - } - return true; -} - -int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) { - v = getCurrentRepVar( v ); - int vn = getVarNum( n ); - vn = vn==-1 ? -1 : getCurrentRepVar( vn ); - n = getCurrentValue( n ); - return addConstraint( p, v, n, vn, polarity, false ); -} - -int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) { - //for handling equalities between variables, and disequalities involving variables - Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")"; - Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl; - Assert( doRemove || n==getCurrentValue( n ) ); - Assert( doRemove || v==getCurrentRepVar( v ) ); - Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) ); - if( polarity ){ - if( vn!=v ){ - if( doRemove ){ - if( vn!=-1 ){ - //if set to this in the opposite direction, clean up opposite instead - // std::map< int, TNode >::iterator itmn = d_match.find( vn ); - if( d_match[vn]==d_vars[v] ){ - return addConstraint( p, vn, d_vars[v], v, true, true ); - }else{ - //unsetting variables equal - std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn ); - if( itd!=d_curr_var_deq.end() ){ - //remove disequalities owned by this - std::vector< TNode > remDeq; - for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ - if( it->second==v ){ - remDeq.push_back( it->first ); - } - } - for( unsigned i=0; i::iterator itm = d_match.find( v ); - - if( vn!=-1 ){ - Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; - //std::map< int, TNode >::iterator itmn = d_match.find( vn ); - if( d_match[v].isNull() ){ - //setting variables equal - bool alreadySet = false; - if( !d_match[vn].isNull() ){ - alreadySet = true; - Assert( !isVar( d_match[vn] ) ); - } - - //copy or check disequalities - std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); - if( itd!=d_curr_var_deq.end() ){ - for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ - Node dv = getCurrentValue( it->first ); - if( !alreadySet ){ - if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){ - d_curr_var_deq[vn][dv] = v; - } - }else{ - if( !p->areMatchDisequal( d_match[vn], dv ) ){ - Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; - return -1; - } - } - } - } - if( alreadySet ){ - n = getCurrentValue( n ); - } - }else{ - if( d_match[vn].isNull() ){ - Debug("qcf-match-debug") << " ...Reverse direction" << std::endl; - //set the opposite direction - return addConstraint( p, vn, d_vars[v], v, true, false ); - }else{ - Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl; - //are they currently equal - return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1; - } - } - }else{ - Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; - if( d_match[v].isNull() ){ - }else{ - //compare ground values - Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; - return p->areMatchEqual( d_match[v], n ) ? 0 : -1; - } - } - if( setMatch( p, v, n ) ){ - Debug("qcf-match-debug") << " -> success" << std::endl; - return 1; - }else{ - Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; - return -1; - } - } - }else{ - Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl; - return 0; - } - }else{ - if( vn==v ){ - Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl; - return -1; - }else{ - if( doRemove ){ - Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() ); - d_curr_var_deq[v].erase( n ); - return 1; - }else{ - if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){ - //check if it respects equality - //std::map< int, TNode >::iterator itm = d_match.find( v ); - if( !d_match[v].isNull() ){ - TNode nv = getCurrentValue( n ); - if( !p->areMatchDisequal( nv, d_match[v] ) ){ - Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; - return -1; - } - } - d_curr_var_deq[v][n] = v; - Debug("qcf-match-debug") << " -> success" << std::endl; - return 1; - }else{ - Debug("qcf-match-debug") << " -> redundant disequality" << std::endl; - return 0; - } - } - } - } -} - -bool QuantInfo::isConstrainedVar( int v ) { - if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){ - return true; - }else{ - Node vv = getVar( v ); - //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){ - for( unsigned i=0; i >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){ - for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ - if( it2->first==vv ){ - return true; - } - } - } - return false; - } -} - -bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) { - if( getCurrentCanBeEqual( p, v, n ) ){ - Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; - d_match[v] = n; - return true; - }else{ - return false; - } -} - -bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { - for( int i=0; i::iterator it = d_match.find( i ); - if( !d_match[i].isNull() ){ - if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){ - return true; - } - } - } - return false; -} - -bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) { - if( !d_tconstraints.empty() ){ - //check constraints - for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ - //apply substitution to the tconstraint - Node cons = it->first.substitute( p->getTermDatabase()->d_vars[d_q].begin(), - p->getTermDatabase()->d_vars[d_q].end(), - terms.begin(), terms.end() ); - cons = it->second ? cons : cons.negate(); - if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){ - return true; - } - } - } - return false; -} - -bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { - Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; - Node rew = Rewriter::rewrite( lit ); - if( rew==p->d_false ){ - Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl; - return false; - }else if( rew!=p->d_true ){ - //if checking for conflicts, we must be sure that the constraint is entailed - if( chEnt ){ - //check if it is entailed - Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl; - std::pair et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew ); - ++(p->d_statistics.d_entailment_checks); - Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl; - if( !et.first ){ - Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl; - return false; - }else{ - return true; - } - }else{ - Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl; - return true; - } - }else{ - Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl; - return true; - } -} - -bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) { - //assign values for variables that were unassigned (usually not necessary, but handles corner cases) - bool doFail = false; - bool success = true; - if( doContinue ){ - doFail = true; - success = false; - }else{ - //solve for interpreted symbol matches - // this breaks the invariant that all introduced constraints are over existing terms - for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ - int index = d_tsym_vars[i]; - TNode v = getCurrentValue( d_vars[index] ); - int slv_v = -1; - if( v==d_vars[index] ){ - slv_v = index; - } - Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl; - if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){ - Kind k = d_vars[index].getKind(); - std::vector< TNode > children; - for( unsigned j=0; jd_effort!=QuantConflictFind::effort_conflict ){ - break; - } - }else{ - Node z = p->getZero( k ); - if( !z.isNull() ){ - Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; - assigned.push_back( vn ); - if( !setMatch( p, vn, z ) ){ - success = false; - break; - } - } - } - }else{ - Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl; - children.push_back( vv ); - } - }else{ - Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl; - children.push_back( d_vars[index][j] ); - } - } - if( success ){ - if( slv_v!=-1 ){ - Node lhs; - if( children.empty() ){ - lhs = p->getZero( k ); - }else if( children.size()==1 ){ - lhs = children[0]; - }else{ - lhs = NodeManager::currentNM()->mkNode( k, children ); - } - Node sum; - if( v==d_vars[index] ){ - sum = lhs; - }else{ - if( p->d_effort==QuantConflictFind::effort_conflict ){ - Kind kn = k; - if( d_vars[index].getKind()==PLUS ){ - kn = MINUS; - } - if( kn!=k ){ - sum = NodeManager::currentNM()->mkNode( kn, v, lhs ); - } - } - } - if( !sum.isNull() ){ - assigned.push_back( slv_v ); - Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; - if( !setMatch( p, slv_v, sum ) ){ - success = false; - } - p->d_tempCache.push_back( sum ); - } - }else{ - //must show that constraint is met - Node sum = NodeManager::currentNM()->mkNode( k, children ); - Node eq = sum.eqNode( v ); - if( !entailmentTest( p, eq ) ){ - success = false; - } - p->d_tempCache.push_back( sum ); - } - } - } - - if( !success ){ - break; - } - } - if( success ){ - //check what is left to assign - d_unassigned.clear(); - d_unassigned_tn.clear(); - std::vector< int > unassigned[2]; - std::vector< TypeNode > unassigned_tn[2]; - for( int i=0; i=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){ - invalidMatch = false; - if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){ - //check if it has now been assigned - if( d_una_indexreset( p, true, this ); - d_una_eqc_count.push_back( 0 ); - } - }else{ - d_una_eqc_count.push_back( 0 ); - } - }else{ - bool failed = false; - if( !doFail ){ - if( d_una_indexgetNextMatch( p, this ) ){ - Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl; - d_una_index++; - }else{ - failed = true; - Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl; - } - }else{ - Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 ); - if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){ - int currIndex = d_una_eqc_count[d_una_index]; - d_una_eqc_count[d_una_index]++; - Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; - if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){ - d_match_term[d_unassigned[d_una_index]] = TNode::null(); - Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; - d_una_index++; - }else{ - Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl; - invalidMatch = true; - } - }else{ - failed = true; - Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl; - } - } - } - if( doFail || failed ){ - do{ - if( !doFail ){ - d_una_eqc_count.pop_back(); - }else{ - doFail = false; - } - d_una_index--; - }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 ); - } - } - } - success = d_una_index>=0; - if( success ){ - doFail = true; - Trace("qcf-check-unassign") << " Try: " << std::endl; - for( unsigned i=0; i " << d_match[ui] << std::endl; - } - } - } - }while( success && isMatchSpurious( p ) ); - } - if( success ){ - for( unsigned i=0; i " << d_match[ui] << std::endl; - } - } - return true; - }else{ - for( unsigned i=0; i& terms ){ - for( unsigned i=0; igetCurrentValue( qi->d_match[i] ); - int repVar = getCurrentRepVar( i ); - Node cv; - //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar ); - if( !d_match_term[repVar].isNull() ){ - cv = d_match_term[repVar]; - }else{ - cv = d_match[repVar]; - } - Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl; - terms.push_back( cv ); - } -} - -void QuantInfo::revertMatch( std::vector< int >& assigned ) { - for( unsigned i=0; i "; - if( !d_match[i].isNull() ){ - Trace(c) << d_match[i]; - }else{ - Trace(c) << "(unassigned) "; - } - if( !d_curr_var_deq[i].empty() ){ - Trace(c) << ", DEQ{ "; - for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){ - Trace(c) << it->first << " "; - } - Trace(c) << "}"; - } - if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){ - Trace(c) << ", EXP : " << d_match_term[i]; - } - Trace(c) << std::endl; - } - if( !d_tconstraints.empty() ){ - Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl; - for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ - Trace(c) << " " << it->first << " -> " << it->second << std::endl; - } - } -} - -MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){ - Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; - std::vector< Node > qni_apps; - d_qni_size = 0; - if( isVar ){ - Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() ); - if( n.getKind()==ITE ){ - d_type = typ_ite_var; - d_type_not = false; - d_n = n; - d_children.push_back( MatchGen( qi, d_n[0] ) ); - if( d_children[0].isValid() ){ - d_type = typ_ite_var; - for( unsigned i=1; i<=2; i++ ){ - Node nn = n.eqNode( n[i] ); - d_children.push_back( MatchGen( qi, nn ) ); - d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 ); - if( !d_children[d_children.size()-1].isValid() ){ - setInvalid(); - break; - } - } - }else{ - d_type = typ_invalid; - } - }else{ - d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; - d_qni_var_num[0] = qi->getVarNum( n ); - d_qni_size++; - d_type_not = false; - d_n = n; - //Node f = getOperator( n ); - for( unsigned j=0; jisVar( nn ) ){ - int v = qi->d_var_num[nn]; - Trace("qcf-qregister-debug") << " is var #" << v << std::endl; - d_qni_var_num[d_qni_size] = v; - //qi->addFuncParent( v, f, j ); - }else{ - Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl; - d_qni_gterm[d_qni_size] = nn; - } - d_qni_size++; - } - } - }else{ - if( n.hasBoundVar() ){ - d_type_not = false; - d_n = n; - if( d_n.getKind()==NOT ){ - d_n = d_n[0]; - d_type_not = !d_type_not; - } - - if( isHandledBoolConnective( d_n ) ){ - //non-literals - d_type = typ_formula; - for( unsigned i=0; id_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) ); - //make it a built-in constraint instead - for( unsigned i=0; i<2; i++ ){ - if( p->d_qinfo[q].isVar( cn[i] ) ){ - int v = p->d_qinfo[q].getVarNum( cn[i] ); - Node cno = cn[i==0 ? 1 : 0]; - p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno ); - break; - } - } - d_children.pop_back(); - } - */ - } - }else{ - d_type = typ_invalid; - //literals - if( isHandledUfTerm( d_n ) ){ - Assert( qi->isVar( d_n ) ); - d_type = typ_pred; - }else if( d_n.getKind()==BOUND_VARIABLE ){ - Assert( d_n.getType().isBoolean() ); - d_type = typ_bool_var; - }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){ - for( unsigned i=0; iisVar( d_n[i] ) ){ - Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl; - } - Assert( qi->isVar( d_n[i] ) ); - if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){ - d_qni_var_num[i+1] = qi->d_var_num[d_n[i]]; - } - }else{ - d_qni_gterm[i] = d_n[i]; - } - } - d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint; - Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl; - } - } - }else{ - //we will just evaluate - d_n = n; - d_type = typ_ground; - } - //if( d_type!=typ_invalid ){ - //determine an efficient children ordering - //if( !d_children.empty() ){ - //for( unsigned i=0; i& cbvars ) { - int v = qi->getVarNum( n ); - if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ - cbvars.push_back( v ); - } - for( unsigned i=0; i& bvars ) { - Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl; - bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ); - std::map< int, std::vector< int > > c_to_vars; - std::map< int, std::vector< int > > vars_to_c; - std::map< int, int > vb_count; - std::map< int, int > vu_count; - std::vector< bool > assigned; - Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; - for( unsigned i=0; i::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){ - d_qni_gterm_rep[it->first] = p->getRepresentative( it->second ); - } - if( d_type==typ_ground ){ - int e = p->evaluate( d_n ); - if( e==1 ){ - d_ground_eval[0] = p->d_true; - }else if( e==-1 ){ - d_ground_eval[0] = p->d_false; - } - }else if( d_type==typ_eq ){ - for( unsigned i=0; ievaluateTerm( d_n[i] ); - } - } - } - d_qni_bound_cons.clear(); - d_qni_bound_cons_var.clear(); - d_qni_bound.clear(); -} - -void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { - d_tgt = d_type_not ? !tgt : tgt; - Debug("qcf-match") << " Reset for : " << d_n << ", type : "; - debugPrintType( "qcf-match", d_type ); - Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl; - d_qn.clear(); - d_qni.clear(); - d_qni_bound.clear(); - d_child_counter = -1; - d_tgt_orig = d_tgt; - - //set up processing matches - if( d_type==typ_invalid ){ - //do nothing - }else if( d_type==typ_ground ){ - if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ - d_child_counter = 0; - } - }else if( d_type==typ_bool_var ){ - //get current value of the variable - TNode n = qi->getCurrentValue( d_n ); - int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); - if( vn==-1 ){ - //evaluate the value, see if it is compatible - int e = p->evaluate( n ); - if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ - d_child_counter = 0; - } - }else{ - //unassigned, set match to true/false - d_qni_bound[0] = vn; - qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false ); - d_child_counter = 0; - } - if( d_child_counter==0 ){ - d_qn.push_back( NULL ); - } - }else if( d_type==typ_var ){ - Assert( isHandledUfTerm( d_n ) ); - Node f = getOperator( p, d_n ); - Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; - TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f ); - if( qni!=NULL ){ - d_qn.push_back( qni ); - } - d_matched_basis = false; - }else if( d_type==typ_tsym || d_type==typ_tconstraint ){ - for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){ - int repVar = qi->getCurrentRepVar( it->second ); - if( qi->d_match[repVar].isNull() ){ - Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl; - d_qni_bound[it->first] = repVar; - } - } - d_qn.push_back( NULL ); - }else if( d_type==typ_pred || d_type==typ_eq ){ - //add initial constraint - Node nn[2]; - int vn[2]; - if( d_type==typ_pred ){ - nn[0] = qi->getCurrentValue( d_n ); - vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) ); - nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false ); - vn[1] = -1; - d_tgt = true; - }else{ - for( unsigned i=0; i<2; i++ ){ - TNode nc; - std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i ); - if( it!=d_qni_gterm_rep.end() ){ - nc = it->second; - }else{ - nc = d_n[i]; - } - nn[i] = qi->getCurrentValue( nc ); - vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) ); - } - } - bool success; - if( vn[0]==-1 && vn[1]==-1 ){ - //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl; - Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl; - //just compare values - if( d_tgt ){ - success = p->areMatchEqual( nn[0], nn[1] ); - }else{ - if( p->d_effort==QuantConflictFind::effort_conflict ){ - success = p->areDisequal( nn[0], nn[1] ); - }else{ - success = p->areMatchDisequal( nn[0], nn[1] ); - } - } - }else{ - //otherwise, add a constraint to a variable - if( vn[1]!=-1 && vn[0]==-1 ){ - //swap - Node t = nn[1]; - nn[1] = nn[0]; - nn[0] = t; - vn[0] = vn[1]; - vn[1] = -1; - } - Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl; - //add some constraint - int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false ); - success = addc!=-1; - //if successful and non-redundant, store that we need to cleanup this - if( addc==1 ){ - //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl; - for( unsigned i=0; i<2; i++ ){ - if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){ - d_qni_bound[vn[i]] = vn[i]; - } - } - d_qni_bound_cons[vn[0]] = nn[1]; - d_qni_bound_cons_var[vn[0]] = vn[1]; - } - } - //if successful, we will bind values to variables - if( success ){ - d_qn.push_back( NULL ); - } - }else{ - if( d_children.empty() ){ - //add dummy - d_qn.push_back( NULL ); - }else{ - if( d_tgt && d_n.getKind()==FORALL ){ - //do nothing - }else{ - //reset the first child to d_tgt - d_child_counter = 0; - getChild( d_child_counter )->reset( p, d_tgt, qi ); - } - } - } - d_binding = false; - d_wasSet = true; - Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl; -} - -bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { - Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; - debugPrintType( "qcf-match", d_type ); - Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; - if( d_type==typ_invalid || d_type==typ_ground ){ - if( d_child_counter==0 ){ - d_child_counter = -1; - return true; - }else{ - d_wasSet = false; - return false; - } - }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){ - bool success = false; - bool terminate = false; - do { - bool doReset = false; - bool doFail = false; - if( !d_binding ){ - if( doMatching( p, qi ) ){ - Debug("qcf-match-debug") << " - Matching succeeded" << std::endl; - d_binding = true; - d_binding_it = d_qni_bound.begin(); - doReset = true; - //for tconstraint, add constraint - if( d_type==typ_tconstraint ){ - std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n ); - if( it==qi->d_tconstraints.end() ){ - qi->d_tconstraints[d_n] = d_tgt; - //store that we added this constraint - d_qni_bound_cons[0] = d_n; - }else if( d_tgt!=it->second ){ - success = false; - terminate = true; - } - } - }else{ - Debug("qcf-match-debug") << " - Matching failed" << std::endl; - success = false; - terminate = true; - } - }else{ - doFail = true; - } - if( d_binding ){ - //also need to create match for each variable we bound - success = true; - Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = "; - debugPrintType( "qcf-match-debug", d_type ); - Debug("qcf-match-debug") << "..." << std::endl; - - while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ - std::map< int, MatchGen * >::iterator itm; - if( !doFail ){ - Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; - itm = qi->d_var_mg.find( d_binding_it->second ); - } - if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){ - Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; - if( doReset ){ - itm->second->reset( p, true, qi ); - } - if( doFail || !itm->second->getNextMatch( p, qi ) ){ - do { - if( d_binding_it==d_qni_bound.begin() ){ - Debug("qcf-match-debug") << " failed." << std::endl; - success = false; - }else{ - --d_binding_it; - Debug("qcf-match-debug") << " decrement..." << std::endl; - } - }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) ); - doReset = false; - doFail = false; - }else{ - Debug("qcf-match-debug") << " increment..." << std::endl; - ++d_binding_it; - doReset = true; - } - }else{ - Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl; - ++d_binding_it; - doReset = true; - } - } - if( !success ){ - d_binding = false; - }else{ - terminate = true; - if( d_binding_it==d_qni_bound.begin() ){ - d_binding = false; - } - } - } - }while( !terminate ); - //if not successful, clean up the variables you bound - if( !success ){ - if( d_type==typ_eq || d_type==typ_pred ){ - //clean up the constraints you added - for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){ - if( !it->second.isNull() ){ - Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl; - std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first ); - int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1; - //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl; - qi->addConstraint( p, it->first, it->second, vn, d_tgt, true ); - } - } - d_qni_bound_cons.clear(); - d_qni_bound_cons_var.clear(); - d_qni_bound.clear(); - }else{ - //clean up the matches you set - for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ - Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; - Assert( it->secondgetNumVars() ); - qi->d_match[ it->second ] = TNode::null(); - qi->d_match_term[ it->second ] = TNode::null(); - } - d_qni_bound.clear(); - } - if( d_type==typ_tconstraint ){ - //remove constraint if applicable - if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){ - qi->d_tconstraints.erase( d_n ); - d_qni_bound_cons.clear(); - } - } - /* - if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){ - d_matched_basis = true; - Node f = getOperator( d_n ); - TNode mbo = p->getTermDatabase()->getModelBasisOpTerm( f ); - if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){ - success = true; - d_qni_bound[0] = d_qni_var_num[0]; - } - } - */ - } - Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; - d_wasSet = success; - return success; - }else if( d_type==typ_formula || d_type==typ_ite_var ){ - bool success = false; - if( d_child_counter<0 ){ - if( d_child_counter<-1 ){ - success = true; - d_child_counter = -1; - } - }else{ - while( !success && d_child_counter>=0 ){ - //transition system based on d_child_counter - if( d_n.getKind()==OR || d_n.getKind()==AND ){ - if( (d_n.getKind()==AND)==d_tgt ){ - //all children must match simultaneously - if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ - if( d_child_counter<(int)(getNumChildren()-1) ){ - d_child_counter++; - Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl; - getChild( d_child_counter )->reset( p, d_tgt, qi ); - }else{ - success = true; - } - }else{ - //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){ - // d_child_counter--; - //}else{ - d_child_counter--; - //} - } - }else{ - //one child must match - if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){ - if( d_child_counter<(int)(getNumChildren()-1) ){ - d_child_counter++; - Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl; - getChild( d_child_counter )->reset( p, d_tgt, qi ); - }else{ - d_child_counter = -1; - } - }else{ - success = true; - } - } - }else if( d_n.getKind()==IFF ){ - //construct match based on both children - if( d_child_counter%2==0 ){ - if( getChild( 0 )->getNextMatch( p, qi ) ){ - d_child_counter++; - getChild( 1 )->reset( p, d_child_counter==1, qi ); - }else{ - if( d_child_counter==0 ){ - d_child_counter = 2; - getChild( 0 )->reset( p, !d_tgt, qi ); - }else{ - d_child_counter = -1; - } - } - } - if( d_child_counter>=0 && d_child_counter%2==1 ){ - if( getChild( 1 )->getNextMatch( p, qi ) ){ - success = true; - }else{ - d_child_counter--; - } - } - }else if( d_n.getKind()==ITE ){ - if( d_child_counter%2==0 ){ - int index1 = d_child_counter==4 ? 1 : 0; - if( getChild( index1 )->getNextMatch( p, qi ) ){ - d_child_counter++; - getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi ); - }else{ - if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){ - d_child_counter = -1; - }else{ - d_child_counter +=2; - getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi ); - } - } - } - if( d_child_counter>=0 && d_child_counter%2==1 ){ - int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2); - if( getChild( index2 )->getNextMatch( p, qi ) ){ - success = true; - }else{ - d_child_counter--; - } - } - }else if( d_n.getKind()==FORALL ){ - if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ - success = true; - }else{ - d_child_counter = -1; - } - } - } - d_wasSet = success; - Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl; - return success; - } - } - Debug("qcf-match") << " ...already finished for " << d_n << std::endl; - return false; -} - -bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) { - if( d_type==typ_eq ){ - Node n[2]; - for( unsigned i=0; i<2; i++ ){ - Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl; - n[i] = getExplanationTerm( p, qi, d_n[i], exp ); - } - Node eq = n[0].eqNode( n[1] ); - if( !d_tgt_orig ){ - eq = eq.negate(); - } - exp.push_back( eq ); - Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl; - return true; - }else if( d_type==typ_pred ){ - Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl; - Node n = getExplanationTerm( p, qi, d_n, exp ); - if( !d_tgt_orig ){ - n = n.negate(); - } - exp.push_back( n ); - Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl; - return true; - }else if( d_type==typ_formula ){ - Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl; - if( d_n.getKind()==OR || d_n.getKind()==AND ){ - if( (d_n.getKind()==AND)==d_tgt ){ - for( unsigned i=0; igetExplanation( p, qi, exp ) ){ - return false; - } - } - }else{ - return getChild( d_child_counter )->getExplanation( p, qi, exp ); - } - }else if( d_n.getKind()==IFF ){ - for( unsigned i=0; i<2; i++ ){ - if( !getChild( i )->getExplanation( p, qi, exp ) ){ - return false; - } - } - }else if( d_n.getKind()==ITE ){ - for( unsigned i=0; i<3; i++ ){ - bool isActive = ( ( i==0 && d_child_counter!=5 ) || - ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) || - ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) ); - if( isActive ){ - if( !getChild( i )->getExplanation( p, qi, exp ) ){ - return false; - } - } - } - }else{ - return false; - } - return true; - }else{ - return false; - } -} - -Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) { - Node v = qi->getCurrentExpValue( t ); - if( isHandledUfTerm( t ) ){ - for( unsigned i=0; i0 ); - bool invalidMatch; - do { - invalidMatch = false; - Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl; - if( d_qn.size()==d_qni.size()+1 ) { - int index = (int)d_qni.size(); - //initialize - TNode val; - std::map< int, int >::iterator itv = d_qni_var_num.find( index ); - if( itv!=d_qni_var_num.end() ){ - //get the representative variable this variable is equal to - int repVar = qi->getCurrentRepVar( itv->second ); - Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl; - //get the value the rep variable - //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar ); - if( !qi->d_match[repVar].isNull() ){ - val = qi->d_match[repVar]; - Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl; - }else{ - //binding a variable - d_qni_bound[index] = repVar; - std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.begin(); - if( it != d_qn[index]->d_data.end() ) { - d_qni.push_back( it ); - //set the match - if( it->first.getType().isSubtypeOf( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first ) ){ - Debug("qcf-match-debug") << " Binding variable" << std::endl; - if( d_qn.size()second ); - } - }else{ - Debug("qcf-match") << " Binding variable, currently fail." << std::endl; - invalidMatch = true; - } - }else{ - Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl; - d_qn.pop_back(); - } - } - }else{ - Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl; - Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() ); - Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() ); - val = d_qni_gterm_rep[index]; - Assert( !val.isNull() ); - } - if( !val.isNull() ){ - //constrained by val - std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.find( val ); - if( it!=d_qn[index]->d_data.end() ){ - Debug("qcf-match-debug") << " Match" << std::endl; - d_qni.push_back( it ); - if( d_qn.size()second ); - } - }else{ - Debug("qcf-match-debug") << " Failed to match" << std::endl; - d_qn.pop_back(); - } - } - }else{ - Assert( d_qn.size()==d_qni.size() ); - int index = d_qni.size()-1; - //increment if binding this variable - bool success = false; - std::map< int, int >::iterator itb = d_qni_bound.find( index ); - if( itb!=d_qni_bound.end() ){ - d_qni[index]++; - if( d_qni[index]!=d_qn[index]->d_data.end() ){ - success = true; - if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){ - Debug("qcf-match-debug") << " Bind next variable" << std::endl; - if( d_qn.size()second ); - } - }else{ - Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl; - invalidMatch = true; - } - }else{ - qi->d_match[ itb->second ] = TNode::null(); - qi->d_match_term[ itb->second ] = TNode::null(); - Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; - } - }else{ - //TODO : if it equal to something else, also try that - } - //if not incrementing, move to next - if( !success ){ - d_qn.pop_back(); - d_qni.pop_back(); - } - } - }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch ); - if( d_qni.size()==d_qni_size ){ - //Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() ); - //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl; - Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() ); - TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first; - Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl; - qi->d_match_term[d_qni_var_num[0]] = t; - //set the match terms - for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ - Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl; - //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term - if( it->first>0 ){ - Assert( !qi->d_match[ it->second ].isNull() ); - Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) ); - qi->d_match_term[it->second] = t[it->first-1]; - } - //} - } - } - } - } - return !d_qn.empty(); -} - -void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) { - if( isTrace ){ - switch( typ ){ - case typ_invalid: Trace(c) << "invalid";break; - case typ_ground: Trace(c) << "ground";break; - case typ_eq: Trace(c) << "eq";break; - case typ_pred: Trace(c) << "pred";break; - case typ_formula: Trace(c) << "formula";break; - case typ_var: Trace(c) << "var";break; - case typ_ite_var: Trace(c) << "ite_var";break; - case typ_bool_var: Trace(c) << "bool_var";break; - } - }else{ - switch( typ ){ - case typ_invalid: Debug(c) << "invalid";break; - case typ_ground: Debug(c) << "ground";break; - case typ_eq: Debug(c) << "eq";break; - case typ_pred: Debug(c) << "pred";break; - case typ_formula: Debug(c) << "formula";break; - case typ_var: Debug(c) << "var";break; - case typ_ite_var: Debug(c) << "ite_var";break; - case typ_bool_var: Debug(c) << "bool_var";break; - } - } -} - -void MatchGen::setInvalid() { - d_type = typ_invalid; - d_children.clear(); -} - -bool MatchGen::isHandledBoolConnective( TNode n ) { - return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT ); -} - -bool MatchGen::isHandledUfTerm( TNode n ) { - //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || - // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; - return inst::Trigger::isAtomicTriggerKind( n.getKind() ); -} - -Node MatchGen::getOperator( QuantConflictFind * p, Node n ) { - if( isHandledUfTerm( n ) ){ - return p->getTermDatabase()->getOperator( n ); - }else{ - return Node::null(); - } -} - -bool MatchGen::isHandled( TNode n ) { - if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){ - if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){ - return false; - } - for( unsigned i=0; imkConst(true); - d_false = NodeManager::currentNM()->mkConst(false); -} - -Node QuantConflictFind::mkEqNode( Node a, Node b ) { - if( a.getType().isBoolean() ){ - return a.iffNode( b ); - }else{ - return a.eqNode( b ); - } -} - -//-------------------------------------------------- registration - -void QuantConflictFind::registerQuantifier( Node q ) { - if( d_quantEngine->hasOwnership( q, this ) ){ - d_quants.push_back( q ); - d_quant_id[q] = d_quants.size(); - Trace("qcf-qregister") << "Register "; - debugPrintQuant( "qcf-qregister", q ); - Trace("qcf-qregister") << " : " << q << std::endl; - //make QcfNode structure - Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; - d_qinfo[q].initialize( q, q[1] ); - - //debug print - Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; - Trace("qcf-qregister") << " "; - debugPrintQuantBody( "qcf-qregister", q, q[1] ); - Trace("qcf-qregister") << std::endl; - if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ - Trace("qcf-qregister") << " with additional constraints : " << std::endl; - for( unsigned j=q[0].getNumChildren(); jQuantConflictFind::effort_conflict ){ - // ret = -1; - //} - }else if( n.getKind()==NOT ){ - return -evaluate( n[0] ); - }else if( n.getKind()==ITE ){ - int cev1 = evaluate( n[0] ); - int cevc[2] = { 0, 0 }; - for( unsigned i=0; i<2; i++ ){ - if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){ - cevc[i] = evaluate( n[i+1] ); - if( cev1!=0 ){ - ret = cevc[i]; - break; - }else if( cevc[i]==0 ){ - break; - } - } - } - if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){ - ret = cevc[0]; - } - }else if( n.getKind()==IFF ){ - int cev1 = evaluate( n[0] ); - if( cev1!=0 ){ - int cev2 = evaluate( n[1] ); - if( cev2!=0 ){ - ret = cev1==cev2 ? 1 : -1; - } - } - - }else{ - int ssval = 0; - if( n.getKind()==OR ){ - ssval = 1; - }else if( n.getKind()==AND ){ - ssval = -1; - } - bool isUnk = false; - for( unsigned i=0; ihasOwnership( q, this ) ){ - Trace("qcf-proc") << "QCF : assertQuantifier : "; - debugPrintQuant("qcf-proc", q); - Trace("qcf-proc") << std::endl; - d_qassert.push_back( q ); - //set the eqRegistries that this depends on to true - //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){ - // it->first->d_active.set( true ); - //} - } -} - -Node QuantConflictFind::evaluateTerm( Node n ) { - if( MatchGen::isHandledUfTerm( n ) ){ - Node f = MatchGen::getOperator( this, n ); - Node nn; - if( getEqualityEngine()->hasTerm( n ) ){ - nn = getTermDatabase()->existsTerm( f, n ); - }else{ - std::vector< TNode > args; - for( unsigned i=0; id_func_map_trie[f].existsTerm( args ); - } - if( !nn.isNull() ){ - Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; - return getRepresentative( nn ); - }else{ - Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; - return n; - } - }else if( n.getKind()==ITE ){ - int v = evaluate( n[0], false, false ); - if( v==1 ){ - return evaluateTerm( n[1] ); - }else if( v==-1 ){ - return evaluateTerm( n[2] ); - } - } - return getRepresentative( n ); -} - -/** new node */ -void QuantConflictFind::newEqClass( Node n ) { - -} - -/** merge */ -void QuantConflictFind::merge( Node a, Node b ) { - -} - -/** assert disequal */ -void QuantConflictFind::assertDisequal( Node a, Node b ) { - -} - -//-------------------------------------------------- check function - -bool QuantConflictFind::needsCheck( Theory::Effort level ) { - bool performCheck = false; - if( options::quantConflictFind() && !d_conflict ){ - if( level==Theory::EFFORT_LAST_CALL ){ - performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL; - }else if( level==Theory::EFFORT_FULL ){ - performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT; - }else if( level==Theory::EFFORT_STANDARD ){ - performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD; - } - } - return performCheck; -} - -void QuantConflictFind::reset_round( Theory::Effort level ) { - d_needs_computeRelEqr = true; -} - -/** check */ -void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { - if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){ - Trace("qcf-check") << "QCF : check : " << level << std::endl; - if( d_conflict ){ - Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl; - if( level>=Theory::EFFORT_FULL ){ - Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl; - //Assert( false ); - } - }else{ - int addedLemmas = 0; - ++(d_statistics.d_inst_rounds); - double clSet = 0; - int prevEt = 0; - if( Trace.isOn("qcf-engine") ){ - prevEt = d_statistics.d_entailment_checks.getData(); - clSet = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl; - } - computeRelevantEqr(); - - //determine order for quantified formulas - std::vector< Node > qorder; - std::map< Node, bool > qassert; - //mark which are asserted - for( unsigned i=0; id_mg->isValid() ){ - Trace("qcf-check") << "Check quantified formula "; - debugPrintQuant("qcf-check", q); - Trace("qcf-check") << " : " << q << "..." << std::endl; - - Trace("qcf-check-debug") << "Reset round..." << std::endl; - qi->reset_round( this ); - //try to make a matches making the body false - Trace("qcf-check-debug") << "Get next match..." << std::endl; - while( qi->d_mg->getNextMatch( this, qi ) ){ - Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl; - qi->debugPrintMatch("qcf-inst"); - Trace("qcf-inst") << std::endl; - std::vector< int > assigned; - if( !qi->isMatchSpurious( this ) ){ - if( qi->completeMatch( this, assigned ) ){ - std::vector< Node > terms; - qi->getMatch( terms ); - if( !qi->isTConstraintSpurious( this, terms ) ){ - if( Debug.isOn("qcf-check-inst") ){ - //if( e==effort_conflict ){ - Node inst = d_quantEngine->getInstantiation( q, terms ); - Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; - Assert( evaluate( inst )!=1 ); - Assert( evaluate( inst )==-1 || e>effort_conflict ); - //} - } - if( d_quantEngine->addInstantiation( q, terms, false ) ){ - Trace("qcf-check") << " ... Added instantiation" << std::endl; - Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; - qi->debugPrintMatch("qcf-inst"); - Trace("qcf-inst") << std::endl; - ++addedLemmas; - if( e==effort_conflict ){ - d_quant_order.insert( d_quant_order.begin(), q ); - d_conflict.set( true ); - ++(d_statistics.d_conflict_inst); - break; - }else if( e==effort_prop_eq ){ - ++(d_statistics.d_prop_inst); - } - }else{ - Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; - //Assert( false ); - } - } - //clean up assigned - qi->revertMatch( assigned ); - d_tempCache.clear(); - }else{ - Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl; - } - }else{ - Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl; - } - } - if( d_conflict ){ - break; - } - } - } - if( addedLemmas>0 ){ - break; - } - } - if( Trace.isOn("qcf-engine") ){ - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet); - if( addedLemmas>0 ){ - Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) ); - Trace("qcf-engine") << ", addedLemmas = " << addedLemmas; - } - Trace("qcf-engine") << std::endl; - int currEt = d_statistics.d_entailment_checks.getData(); - if( currEt!=prevEt ){ - Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl; - } - } - Trace("qcf-check2") << "QCF : finished check : " << level << std::endl; - } - } -} - -void QuantConflictFind::computeRelevantEqr() { - if( d_needs_computeRelEqr ){ - d_needs_computeRelEqr = false; - Trace("qcf-check") << "Compute relevant equalities..." << std::endl; - //d_uf_terms.clear(); - //d_eqc_uf_terms.clear(); - d_eqcs.clear(); - d_model_basis.clear(); - //d_arg_reps.clear(); - //double clSet = 0; - //if( Trace.isOn("qcf-opt") ){ - // clSet = double(clock())/double(CLOCKS_PER_SEC); - //} - - //long nTermst = 0; - //long nTerms = 0; - //long nEqc = 0; - - //which nodes are irrelevant for disequality matches - std::map< TNode, bool > irrelevant_dnode; - //now, store matches - eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); - while( !eqcs_i.isFinished() ){ - //nEqc++; - Node r = (*eqcs_i); - if( getTermDatabase()->hasTermCurrent( r ) ){ - TypeNode rtn = r.getType(); - if( options::qcfMode()==QCF_MC ){ - std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn ); - if( itt==d_eqcs.end() ){ - Node mb = getTermDatabase()->getModelBasisTerm( rtn ); - if( !getEqualityEngine()->hasTerm( mb ) ){ - Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl; - Assert( false ); - } - Node mbr = getRepresentative( mb ); - if( mbr!=r ){ - d_eqcs[rtn].push_back( mbr ); - } - d_eqcs[rtn].push_back( r ); - d_model_basis[rtn] = mb; - }else{ - itt->second.push_back( r ); - } - }else{ - d_eqcs[rtn].push_back( r ); - } - } - ++eqcs_i; - } - /* - if( Trace.isOn("qcf-opt") ){ - double clSet2 = double(clock())/double(CLOCKS_PER_SEC); - Trace("qcf-opt") << "Compute rel eqc : " << std::endl; - Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl; - Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl; - Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl; - } - */ - } -} - - -//-------------------------------------------------- debugging - - -void QuantConflictFind::debugPrint( const char * c ) { - //print the equivalance classes - Trace(c) << "----------EQ classes" << std::endl; - eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); - while( !eqcs_i.isFinished() ){ - Node n = (*eqcs_i); - //if( !n.getType().isInteger() ){ - Trace(c) << " - " << n << " : {"; - eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() ); - bool pr = false; - while( !eqc_i.isFinished() ){ - Node nn = (*eqc_i); - if( nn.getKind()!=EQUAL && nn!=n ){ - Trace(c) << (pr ? "," : "" ) << " " << nn; - pr = true; - } - ++eqc_i; - } - Trace(c) << (pr ? " " : "" ) << "}" << std::endl; - /* - EqcInfo * eqcn = getEqcInfo( n, false ); - if( eqcn ){ - Trace(c) << " DEQ : {"; - pr = false; - for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){ - if( (*it).second ){ - Trace(c) << (pr ? "," : "" ) << " " << (*it).first; - pr = true; - } - } - Trace(c) << (pr ? " " : "" ) << "}" << std::endl; - } - //} - */ - ++eqcs_i; - } -} - -void QuantConflictFind::debugPrintQuant( const char * c, Node q ) { - Trace(c) << "Q" << d_quant_id[q]; -} - -void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) { - if( n.getNumChildren()==0 ){ - Trace(c) << n; - }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){ - Trace(c) << "?x" << d_qinfo[q].d_var_num[n]; - }else{ - Trace(c) << "("; - if( n.getKind()==APPLY_UF ){ - Trace(c) << n.getOperator(); - }else{ - Trace(c) << n.getKind(); - } - for( unsigned i=0; i::iterator it = d_zero.find( k ); - if( it==d_zero.end() ){ - Node nn; - if( k==PLUS ){ - nn = NodeManager::currentNM()->mkConst( Rational(0) ); - } - d_zero[k] = nn; - return nn; - }else{ - return it->second; - } -} - - -} +/********************* */ +/*! \file quant_conflict_find.cpp + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2014 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief quant conflict find class + ** + **/ + +#include + +#include "theory/quantifiers/quant_conflict_find.h" +#include "theory/quantifiers/quant_util.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/trigger.h" + +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::theory; +using namespace CVC4::theory::quantifiers; +using namespace std; + +namespace CVC4 { + + + +void QuantInfo::initialize( Node q, Node qn ) { + d_q = q; + for( unsigned i=0; iisValid() ){ + /* + for( unsigned j=0; jsetInvalid(); + break; + } + } + */ + if( d_mg->isValid() ){ + for( unsigned j=q[0].getNumChildren(); jisValid() ){ + Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; + d_mg->setInvalid(); + break; + }else{ + std::vector< int > bvars; + d_var_mg[j]->determineVariableOrder( this, bvars ); + } + } + } + if( d_mg->isValid() ){ + std::vector< int > bvars; + d_mg->determineVariableOrder( this, bvars ); + } + } + }else{ + Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; + } + Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl; +} + +void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { + Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; + if( n.getKind()==FORALL ){ + registerNode( n[1], hasPol, pol, true ); + }else{ + if( !MatchGen::isHandledBoolConnective( n ) ){ + if( n.hasBoundVar() ){ + //literals + if( n.getKind()==EQUAL ){ + for( unsigned i=0; id_parent = qcf; + //qcf->d_child[i] = qcfc; + registerNode( n[i], newHasPol, newPol, beneathQuant ); + } + } + } +} + +void QuantInfo::flatten( Node n, bool beneathQuant ) { + Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl; + if( n.hasBoundVar() ){ + if( n.getKind()==BOUND_VARIABLE ){ + d_inMatchConstraint[n] = true; + } + //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){ + if( d_var_num.find( n )==d_var_num.end() ){ + Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; + d_var_num[n] = d_vars.size(); + d_vars.push_back( n ); + d_var_types.push_back( n.getType() ); + d_match.push_back( TNode::null() ); + d_match_term.push_back( TNode::null() ); + if( n.getKind()==ITE ){ + registerNode( n, false, false ); + }else{ + for( unsigned i=0; i >::iterator it = d_var_constraint[r].begin(); + it != d_var_constraint[r].end(); ++it ){ + for( unsigned j=0; jsecond.size(); j++ ){ + Node rr = it->second[j]; + if( !isVar( rr ) ){ + rr = p->getRepresentative( rr ); + } + if( addConstraint( p, it->first, rr, r==0 )==-1 ){ + d_var_constraint[0].clear(); + d_var_constraint[1].clear(); + //quantified formula is actually equivalent to true + Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl; + d_mg->d_children.clear(); + d_mg->d_n = NodeManager::currentNM()->mkConst( true ); + d_mg->d_type = MatchGen::typ_ground; + return; + } + } + } + } + d_mg->reset_round( p ); + for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){ + it->second->reset_round( p ); + } + //now, reset for matching + d_mg->reset( p, false, this ); +} + +int QuantInfo::getCurrentRepVar( int v ) { + if( v!=-1 && !d_match[v].isNull() ){ + int vn = getVarNum( d_match[v] ); + if( vn!=-1 ){ + //int vr = getCurrentRepVar( vn ); + //d_match[v] = d_vars[vr]; + //return vr; + return getCurrentRepVar( vn ); + } + } + return v; +} + +TNode QuantInfo::getCurrentValue( TNode n ) { + int v = getVarNum( n ); + if( v==-1 ){ + return n; + }else{ + if( d_match[v].isNull() ){ + return n; + }else{ + Assert( getVarNum( d_match[v] )!=v ); + return getCurrentValue( d_match[v] ); + } + } +} + +TNode QuantInfo::getCurrentExpValue( TNode n ) { + int v = getVarNum( n ); + if( v==-1 ){ + return n; + }else{ + if( d_match[v].isNull() ){ + return n; + }else{ + Assert( getVarNum( d_match[v] )!=v ); + if( d_match_term[v].isNull() ){ + return getCurrentValue( d_match[v] ); + }else{ + return d_match_term[v]; + } + } + } +} + +bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) { + //check disequalities + std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); + if( itd!=d_curr_var_deq.end() ){ + for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ + Node cv = getCurrentValue( it->first ); + Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl; + if( cv==n ){ + return false; + }else if( chDiseq && !isVar( n ) && !isVar( cv ) ){ + //they must actually be disequal if we are looking for conflicts + if( !p->areDisequal( n, cv ) ){ + //TODO : check for entailed disequal + + return false; + } + } + } + } + return true; +} + +int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ) { + v = getCurrentRepVar( v ); + int vn = getVarNum( n ); + vn = vn==-1 ? -1 : getCurrentRepVar( vn ); + n = getCurrentValue( n ); + return addConstraint( p, v, n, vn, polarity, false ); +} + +int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ) { + //for handling equalities between variables, and disequalities involving variables + Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")"; + Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl; + Assert( doRemove || n==getCurrentValue( n ) ); + Assert( doRemove || v==getCurrentRepVar( v ) ); + Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) ); + if( polarity ){ + if( vn!=v ){ + if( doRemove ){ + if( vn!=-1 ){ + //if set to this in the opposite direction, clean up opposite instead + // std::map< int, TNode >::iterator itmn = d_match.find( vn ); + if( d_match[vn]==d_vars[v] ){ + return addConstraint( p, vn, d_vars[v], v, true, true ); + }else{ + //unsetting variables equal + std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( vn ); + if( itd!=d_curr_var_deq.end() ){ + //remove disequalities owned by this + std::vector< TNode > remDeq; + for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ + if( it->second==v ){ + remDeq.push_back( it->first ); + } + } + for( unsigned i=0; i::iterator itm = d_match.find( v ); + + if( vn!=-1 ){ + Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; + //std::map< int, TNode >::iterator itmn = d_match.find( vn ); + if( d_match[v].isNull() ){ + //setting variables equal + bool alreadySet = false; + if( !d_match[vn].isNull() ){ + alreadySet = true; + Assert( !isVar( d_match[vn] ) ); + } + + //copy or check disequalities + std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v ); + if( itd!=d_curr_var_deq.end() ){ + for( std::map< TNode, int >::iterator it = itd->second.begin(); it != itd->second.end(); ++it ){ + Node dv = getCurrentValue( it->first ); + if( !alreadySet ){ + if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){ + d_curr_var_deq[vn][dv] = v; + } + }else{ + if( !p->areMatchDisequal( d_match[vn], dv ) ){ + Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; + return -1; + } + } + } + } + if( alreadySet ){ + n = getCurrentValue( n ); + } + }else{ + if( d_match[vn].isNull() ){ + Debug("qcf-match-debug") << " ...Reverse direction" << std::endl; + //set the opposite direction + return addConstraint( p, vn, d_vars[v], v, true, false ); + }else{ + Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl; + //are they currently equal + return p->areMatchEqual( d_match[v], d_match[vn] ) ? 0 : -1; + } + } + }else{ + Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; + if( d_match[v].isNull() ){ + }else{ + //compare ground values + Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; + return p->areMatchEqual( d_match[v], n ) ? 0 : -1; + } + } + if( setMatch( p, v, n ) ){ + Debug("qcf-match-debug") << " -> success" << std::endl; + return 1; + }else{ + Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; + return -1; + } + } + }else{ + Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl; + return 0; + } + }else{ + if( vn==v ){ + Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl; + return -1; + }else{ + if( doRemove ){ + Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() ); + d_curr_var_deq[v].erase( n ); + return 1; + }else{ + if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){ + //check if it respects equality + //std::map< int, TNode >::iterator itm = d_match.find( v ); + if( !d_match[v].isNull() ){ + TNode nv = getCurrentValue( n ); + if( !p->areMatchDisequal( nv, d_match[v] ) ){ + Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl; + return -1; + } + } + d_curr_var_deq[v][n] = v; + Debug("qcf-match-debug") << " -> success" << std::endl; + return 1; + }else{ + Debug("qcf-match-debug") << " -> redundant disequality" << std::endl; + return 0; + } + } + } + } +} + +bool QuantInfo::isConstrainedVar( int v ) { + if( d_curr_var_deq.find( v )!=d_curr_var_deq.end() && !d_curr_var_deq[v].empty() ){ + return true; + }else{ + Node vv = getVar( v ); + //for( std::map< int, TNode >::iterator it = d_match.begin(); it != d_match.end(); ++it ){ + for( unsigned i=0; i >::iterator it = d_curr_var_deq.begin(); it != d_curr_var_deq.end(); ++it ){ + for( std::map< TNode, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ + if( it2->first==vv ){ + return true; + } + } + } + return false; + } +} + +bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n ) { + if( getCurrentCanBeEqual( p, v, n ) ){ + Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; + d_match[v] = n; + return true; + }else{ + return false; + } +} + +bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { + for( int i=0; i::iterator it = d_match.find( i ); + if( !d_match[i].isNull() ){ + if( !getCurrentCanBeEqual( p, i, d_match[i], p->d_effort==QuantConflictFind::effort_conflict ) ){ + return true; + } + } + } + return false; +} + +bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) { + if( !d_tconstraints.empty() ){ + //check constraints + for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ + //apply substitution to the tconstraint + Node cons = it->first.substitute( p->getTermDatabase()->d_vars[d_q].begin(), + p->getTermDatabase()->d_vars[d_q].end(), + terms.begin(), terms.end() ); + cons = it->second ? cons : cons.negate(); + if( !entailmentTest( p, cons, p->d_effort==QuantConflictFind::effort_conflict ) ){ + return true; + } + } + } + return false; +} + +bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { + Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; + Node rew = Rewriter::rewrite( lit ); + if( rew==p->d_false ){ + Trace("qcf-tconstraint-debug") << "...constraint " << lit << " is disentailed (rewrites to false)." << std::endl; + return false; + }else if( rew!=p->d_true ){ + //if checking for conflicts, we must be sure that the constraint is entailed + if( chEnt ){ + //check if it is entailed + Trace("qcf-tconstraint-debug") << "Check entailment of " << rew << "..." << std::endl; + std::pair et = p->getQuantifiersEngine()->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, rew ); + ++(p->d_statistics.d_entailment_checks); + Trace("qcf-tconstraint-debug") << "ET result : " << et.first << " " << et.second << std::endl; + if( !et.first ){ + Trace("qcf-tconstraint-debug") << "...cannot show entailment of " << rew << "." << std::endl; + return false; + }else{ + return true; + } + }else{ + Trace("qcf-tconstraint-debug") << "...does not need to be entailed." << std::endl; + return true; + } + }else{ + Trace("qcf-tconstraint-debug") << "...rewrites to true." << std::endl; + return true; + } +} + +bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) { + //assign values for variables that were unassigned (usually not necessary, but handles corner cases) + bool doFail = false; + bool success = true; + if( doContinue ){ + doFail = true; + success = false; + }else{ + //solve for interpreted symbol matches + // this breaks the invariant that all introduced constraints are over existing terms + for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ + int index = d_tsym_vars[i]; + TNode v = getCurrentValue( d_vars[index] ); + int slv_v = -1; + if( v==d_vars[index] ){ + slv_v = index; + } + Trace("qcf-tconstraint-debug") << "Solve " << d_vars[index] << " = " << v << " " << d_vars[index].getKind() << std::endl; + if( d_vars[index].getKind()==PLUS || d_vars[index].getKind()==MULT ){ + Kind k = d_vars[index].getKind(); + std::vector< TNode > children; + for( unsigned j=0; jd_effort!=QuantConflictFind::effort_conflict ){ + break; + } + }else{ + Node z = p->getZero( k ); + if( !z.isNull() ){ + Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; + assigned.push_back( vn ); + if( !setMatch( p, vn, z ) ){ + success = false; + break; + } + } + } + }else{ + Trace("qcf-tconstraint-debug") << "...sum value " << vv << std::endl; + children.push_back( vv ); + } + }else{ + Trace("qcf-tconstraint-debug") << "...sum " << d_vars[index][j] << std::endl; + children.push_back( d_vars[index][j] ); + } + } + if( success ){ + if( slv_v!=-1 ){ + Node lhs; + if( children.empty() ){ + lhs = p->getZero( k ); + }else if( children.size()==1 ){ + lhs = children[0]; + }else{ + lhs = NodeManager::currentNM()->mkNode( k, children ); + } + Node sum; + if( v==d_vars[index] ){ + sum = lhs; + }else{ + if( p->d_effort==QuantConflictFind::effort_conflict ){ + Kind kn = k; + if( d_vars[index].getKind()==PLUS ){ + kn = MINUS; + } + if( kn!=k ){ + sum = NodeManager::currentNM()->mkNode( kn, v, lhs ); + } + } + } + if( !sum.isNull() ){ + assigned.push_back( slv_v ); + Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; + if( !setMatch( p, slv_v, sum ) ){ + success = false; + } + p->d_tempCache.push_back( sum ); + } + }else{ + //must show that constraint is met + Node sum = NodeManager::currentNM()->mkNode( k, children ); + Node eq = sum.eqNode( v ); + if( !entailmentTest( p, eq ) ){ + success = false; + } + p->d_tempCache.push_back( sum ); + } + } + } + + if( !success ){ + break; + } + } + if( success ){ + //check what is left to assign + d_unassigned.clear(); + d_unassigned_tn.clear(); + std::vector< int > unassigned[2]; + std::vector< TypeNode > unassigned_tn[2]; + for( int i=0; i=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){ + invalidMatch = false; + if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){ + //check if it has now been assigned + if( d_una_indexreset( p, true, this ); + d_una_eqc_count.push_back( 0 ); + } + }else{ + d_una_eqc_count.push_back( 0 ); + } + }else{ + bool failed = false; + if( !doFail ){ + if( d_una_indexgetNextMatch( p, this ) ){ + Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl; + d_una_index++; + }else{ + failed = true; + Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl; + } + }else{ + Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 ); + if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){ + int currIndex = d_una_eqc_count[d_una_index]; + d_una_eqc_count[d_una_index]++; + Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; + if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){ + d_match_term[d_unassigned[d_una_index]] = TNode::null(); + Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; + d_una_index++; + }else{ + Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl; + invalidMatch = true; + } + }else{ + failed = true; + Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl; + } + } + } + if( doFail || failed ){ + do{ + if( !doFail ){ + d_una_eqc_count.pop_back(); + }else{ + doFail = false; + } + d_una_index--; + }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 ); + } + } + } + success = d_una_index>=0; + if( success ){ + doFail = true; + Trace("qcf-check-unassign") << " Try: " << std::endl; + for( unsigned i=0; i " << d_match[ui] << std::endl; + } + } + } + }while( success && isMatchSpurious( p ) ); + } + if( success ){ + for( unsigned i=0; i " << d_match[ui] << std::endl; + } + } + return true; + }else{ + for( unsigned i=0; i& terms ){ + for( unsigned i=0; igetCurrentValue( qi->d_match[i] ); + int repVar = getCurrentRepVar( i ); + Node cv; + //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar ); + if( !d_match_term[repVar].isNull() ){ + cv = d_match_term[repVar]; + }else{ + cv = d_match[repVar]; + } + Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl; + terms.push_back( cv ); + } +} + +void QuantInfo::revertMatch( std::vector< int >& assigned ) { + for( unsigned i=0; i "; + if( !d_match[i].isNull() ){ + Trace(c) << d_match[i]; + }else{ + Trace(c) << "(unassigned) "; + } + if( !d_curr_var_deq[i].empty() ){ + Trace(c) << ", DEQ{ "; + for( std::map< TNode, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){ + Trace(c) << it->first << " "; + } + Trace(c) << "}"; + } + if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){ + Trace(c) << ", EXP : " << d_match_term[i]; + } + Trace(c) << std::endl; + } + if( !d_tconstraints.empty() ){ + Trace(c) << "ADDITIONAL CONSTRAINTS : " << std::endl; + for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ + Trace(c) << " " << it->first << " -> " << it->second << std::endl; + } + } +} + +MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ){ + Trace("qcf-qregister-debug") << "Make match gen for " << n << ", isVar = " << isVar << std::endl; + std::vector< Node > qni_apps; + d_qni_size = 0; + if( isVar ){ + Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() ); + if( n.getKind()==ITE ){ + d_type = typ_ite_var; + d_type_not = false; + d_n = n; + d_children.push_back( MatchGen( qi, d_n[0] ) ); + if( d_children[0].isValid() ){ + d_type = typ_ite_var; + for( unsigned i=1; i<=2; i++ ){ + Node nn = n.eqNode( n[i] ); + d_children.push_back( MatchGen( qi, nn ) ); + d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 ); + if( !d_children[d_children.size()-1].isValid() ){ + setInvalid(); + break; + } + } + }else{ + d_type = typ_invalid; + } + }else{ + d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; + d_qni_var_num[0] = qi->getVarNum( n ); + d_qni_size++; + d_type_not = false; + d_n = n; + //Node f = getOperator( n ); + for( unsigned j=0; jisVar( nn ) ){ + int v = qi->d_var_num[nn]; + Trace("qcf-qregister-debug") << " is var #" << v << std::endl; + d_qni_var_num[d_qni_size] = v; + //qi->addFuncParent( v, f, j ); + }else{ + Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl; + d_qni_gterm[d_qni_size] = nn; + } + d_qni_size++; + } + } + }else{ + if( n.hasBoundVar() ){ + d_type_not = false; + d_n = n; + if( d_n.getKind()==NOT ){ + d_n = d_n[0]; + d_type_not = !d_type_not; + } + + if( isHandledBoolConnective( d_n ) ){ + //non-literals + d_type = typ_formula; + for( unsigned i=0; id_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) ); + //make it a built-in constraint instead + for( unsigned i=0; i<2; i++ ){ + if( p->d_qinfo[q].isVar( cn[i] ) ){ + int v = p->d_qinfo[q].getVarNum( cn[i] ); + Node cno = cn[i==0 ? 1 : 0]; + p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno ); + break; + } + } + d_children.pop_back(); + } + */ + } + }else{ + d_type = typ_invalid; + //literals + if( isHandledUfTerm( d_n ) ){ + Assert( qi->isVar( d_n ) ); + d_type = typ_pred; + }else if( d_n.getKind()==BOUND_VARIABLE ){ + Assert( d_n.getType().isBoolean() ); + d_type = typ_bool_var; + }else if( d_n.getKind()==EQUAL || options::qcfTConstraint() ){ + for( unsigned i=0; iisVar( d_n[i] ) ){ + Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl; + } + Assert( qi->isVar( d_n[i] ) ); + if( d_n.getKind()!=EQUAL && qi->isVar( d_n[i] ) ){ + d_qni_var_num[i+1] = qi->d_var_num[d_n[i]]; + } + }else{ + d_qni_gterm[i] = d_n[i]; + } + } + d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint; + Trace("qcf-tconstraint") << "T-Constraint : " << d_n << std::endl; + } + } + }else{ + //we will just evaluate + d_n = n; + d_type = typ_ground; + } + //if( d_type!=typ_invalid ){ + //determine an efficient children ordering + //if( !d_children.empty() ){ + //for( unsigned i=0; i& cbvars ) { + int v = qi->getVarNum( n ); + if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ + cbvars.push_back( v ); + } + for( unsigned i=0; i& bvars ) { + Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl; + bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ); + std::map< int, std::vector< int > > c_to_vars; + std::map< int, std::vector< int > > vars_to_c; + std::map< int, int > vb_count; + std::map< int, int > vu_count; + std::vector< bool > assigned; + Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; + for( unsigned i=0; i::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){ + d_qni_gterm_rep[it->first] = p->getRepresentative( it->second ); + } + if( d_type==typ_ground ){ + int e = p->evaluate( d_n ); + if( e==1 ){ + d_ground_eval[0] = p->d_true; + }else if( e==-1 ){ + d_ground_eval[0] = p->d_false; + } + }else if( d_type==typ_eq ){ + for( unsigned i=0; ievaluateTerm( d_n[i] ); + } + } + } + d_qni_bound_cons.clear(); + d_qni_bound_cons_var.clear(); + d_qni_bound.clear(); +} + +void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { + d_tgt = d_type_not ? !tgt : tgt; + Debug("qcf-match") << " Reset for : " << d_n << ", type : "; + debugPrintType( "qcf-match", d_type ); + Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << " " << d_children_order.size() << std::endl; + d_qn.clear(); + d_qni.clear(); + d_qni_bound.clear(); + d_child_counter = -1; + d_tgt_orig = d_tgt; + + //set up processing matches + if( d_type==typ_invalid ){ + //do nothing + }else if( d_type==typ_ground ){ + if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ + d_child_counter = 0; + } + }else if( d_type==typ_bool_var ){ + //get current value of the variable + TNode n = qi->getCurrentValue( d_n ); + int vn = qi->getCurrentRepVar( qi->getVarNum( n ) ); + if( vn==-1 ){ + //evaluate the value, see if it is compatible + int e = p->evaluate( n ); + if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){ + d_child_counter = 0; + } + }else{ + //unassigned, set match to true/false + d_qni_bound[0] = vn; + qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false ); + d_child_counter = 0; + } + if( d_child_counter==0 ){ + d_qn.push_back( NULL ); + } + }else if( d_type==typ_var ){ + Assert( isHandledUfTerm( d_n ) ); + Node f = getOperator( p, d_n ); + Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; + TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f ); + if( qni!=NULL ){ + d_qn.push_back( qni ); + } + d_matched_basis = false; + }else if( d_type==typ_tsym || d_type==typ_tconstraint ){ + for( std::map< int, int >::iterator it = d_qni_var_num.begin(); it != d_qni_var_num.end(); ++it ){ + int repVar = qi->getCurrentRepVar( it->second ); + if( qi->d_match[repVar].isNull() ){ + Debug("qcf-match-debug") << "Force matching on child #" << it->first << ", which is var #" << repVar << std::endl; + d_qni_bound[it->first] = repVar; + } + } + d_qn.push_back( NULL ); + }else if( d_type==typ_pred || d_type==typ_eq ){ + //add initial constraint + Node nn[2]; + int vn[2]; + if( d_type==typ_pred ){ + nn[0] = qi->getCurrentValue( d_n ); + vn[0] = qi->getCurrentRepVar( qi->getVarNum( nn[0] ) ); + nn[1] = p->getRepresentative( d_tgt ? p->d_true : p->d_false ); + vn[1] = -1; + d_tgt = true; + }else{ + for( unsigned i=0; i<2; i++ ){ + TNode nc; + std::map< int, TNode >::iterator it = d_qni_gterm_rep.find( i ); + if( it!=d_qni_gterm_rep.end() ){ + nc = it->second; + }else{ + nc = d_n[i]; + } + nn[i] = qi->getCurrentValue( nc ); + vn[i] = qi->getCurrentRepVar( qi->getVarNum( nn[i] ) ); + } + } + bool success; + if( vn[0]==-1 && vn[1]==-1 ){ + //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl; + Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl; + //just compare values + if( d_tgt ){ + success = p->areMatchEqual( nn[0], nn[1] ); + }else{ + if( p->d_effort==QuantConflictFind::effort_conflict ){ + success = p->areDisequal( nn[0], nn[1] ); + }else{ + success = p->areMatchDisequal( nn[0], nn[1] ); + } + } + }else{ + //otherwise, add a constraint to a variable + if( vn[1]!=-1 && vn[0]==-1 ){ + //swap + Node t = nn[1]; + nn[1] = nn[0]; + nn[0] = t; + vn[0] = vn[1]; + vn[1] = -1; + } + Debug("qcf-match-debug") << " reset: add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << std::endl; + //add some constraint + int addc = qi->addConstraint( p, vn[0], nn[1], vn[1], d_tgt, false ); + success = addc!=-1; + //if successful and non-redundant, store that we need to cleanup this + if( addc==1 ){ + //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl; + for( unsigned i=0; i<2; i++ ){ + if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){ + d_qni_bound[vn[i]] = vn[i]; + } + } + d_qni_bound_cons[vn[0]] = nn[1]; + d_qni_bound_cons_var[vn[0]] = vn[1]; + } + } + //if successful, we will bind values to variables + if( success ){ + d_qn.push_back( NULL ); + } + }else{ + if( d_children.empty() ){ + //add dummy + d_qn.push_back( NULL ); + }else{ + if( d_tgt && d_n.getKind()==FORALL ){ + //do nothing + }else{ + //reset the first child to d_tgt + d_child_counter = 0; + getChild( d_child_counter )->reset( p, d_tgt, qi ); + } + } + } + d_binding = false; + d_wasSet = true; + Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl; +} + +bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { + Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; + debugPrintType( "qcf-match", d_type ); + Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; + if( d_type==typ_invalid || d_type==typ_ground ){ + if( d_child_counter==0 ){ + d_child_counter = -1; + return true; + }else{ + d_wasSet = false; + return false; + } + }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var || d_type==typ_tconstraint || d_type==typ_tsym ){ + bool success = false; + bool terminate = false; + do { + bool doReset = false; + bool doFail = false; + if( !d_binding ){ + if( doMatching( p, qi ) ){ + Debug("qcf-match-debug") << " - Matching succeeded" << std::endl; + d_binding = true; + d_binding_it = d_qni_bound.begin(); + doReset = true; + //for tconstraint, add constraint + if( d_type==typ_tconstraint ){ + std::map< Node, bool >::iterator it = qi->d_tconstraints.find( d_n ); + if( it==qi->d_tconstraints.end() ){ + qi->d_tconstraints[d_n] = d_tgt; + //store that we added this constraint + d_qni_bound_cons[0] = d_n; + }else if( d_tgt!=it->second ){ + success = false; + terminate = true; + } + } + }else{ + Debug("qcf-match-debug") << " - Matching failed" << std::endl; + success = false; + terminate = true; + } + }else{ + doFail = true; + } + if( d_binding ){ + //also need to create match for each variable we bound + success = true; + Debug("qcf-match-debug") << " Produce matches for bound variables by " << d_n << ", type = "; + debugPrintType( "qcf-match-debug", d_type ); + Debug("qcf-match-debug") << "..." << std::endl; + + while( ( success && d_binding_it!=d_qni_bound.end() ) || doFail ){ + std::map< int, MatchGen * >::iterator itm; + if( !doFail ){ + Debug("qcf-match-debug") << " check variable " << d_binding_it->second << std::endl; + itm = qi->d_var_mg.find( d_binding_it->second ); + } + if( doFail || ( d_binding_it->first!=0 && itm!=qi->d_var_mg.end() ) ){ + Debug("qcf-match-debug") << " we had bound variable " << d_binding_it->second << ", reset = " << doReset << std::endl; + if( doReset ){ + itm->second->reset( p, true, qi ); + } + if( doFail || !itm->second->getNextMatch( p, qi ) ){ + do { + if( d_binding_it==d_qni_bound.begin() ){ + Debug("qcf-match-debug") << " failed." << std::endl; + success = false; + }else{ + --d_binding_it; + Debug("qcf-match-debug") << " decrement..." << std::endl; + } + }while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) ); + doReset = false; + doFail = false; + }else{ + Debug("qcf-match-debug") << " increment..." << std::endl; + ++d_binding_it; + doReset = true; + } + }else{ + Debug("qcf-match-debug") << " skip..." << d_binding_it->second << std::endl; + ++d_binding_it; + doReset = true; + } + } + if( !success ){ + d_binding = false; + }else{ + terminate = true; + if( d_binding_it==d_qni_bound.begin() ){ + d_binding = false; + } + } + } + }while( !terminate ); + //if not successful, clean up the variables you bound + if( !success ){ + if( d_type==typ_eq || d_type==typ_pred ){ + //clean up the constraints you added + for( std::map< int, TNode >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){ + if( !it->second.isNull() ){ + Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl; + std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first ); + int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1; + //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl; + qi->addConstraint( p, it->first, it->second, vn, d_tgt, true ); + } + } + d_qni_bound_cons.clear(); + d_qni_bound_cons_var.clear(); + d_qni_bound.clear(); + }else{ + //clean up the matches you set + for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ + Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; + Assert( it->secondgetNumVars() ); + qi->d_match[ it->second ] = TNode::null(); + qi->d_match_term[ it->second ] = TNode::null(); + } + d_qni_bound.clear(); + } + if( d_type==typ_tconstraint ){ + //remove constraint if applicable + if( d_qni_bound_cons.find( 0 )!=d_qni_bound_cons.end() ){ + qi->d_tconstraints.erase( d_n ); + d_qni_bound_cons.clear(); + } + } + /* + if( d_type==typ_var && p->d_effort==QuantConflictFind::effort_mc && !d_matched_basis ){ + d_matched_basis = true; + Node f = getOperator( d_n ); + TNode mbo = p->getTermDatabase()->getModelBasisOpTerm( f ); + if( qi->setMatch( p, d_qni_var_num[0], mbo ) ){ + success = true; + d_qni_bound[0] = d_qni_var_num[0]; + } + } + */ + } + Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl; + d_wasSet = success; + return success; + }else if( d_type==typ_formula || d_type==typ_ite_var ){ + bool success = false; + if( d_child_counter<0 ){ + if( d_child_counter<-1 ){ + success = true; + d_child_counter = -1; + } + }else{ + while( !success && d_child_counter>=0 ){ + //transition system based on d_child_counter + if( d_n.getKind()==OR || d_n.getKind()==AND ){ + if( (d_n.getKind()==AND)==d_tgt ){ + //all children must match simultaneously + if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ + if( d_child_counter<(int)(getNumChildren()-1) ){ + d_child_counter++; + Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << std::endl; + getChild( d_child_counter )->reset( p, d_tgt, qi ); + }else{ + success = true; + } + }else{ + //if( std::find( d_independent.begin(), d_independent.end(), d_child_counter )!=d_independent.end() ){ + // d_child_counter--; + //}else{ + d_child_counter--; + //} + } + }else{ + //one child must match + if( !getChild( d_child_counter )->getNextMatch( p, qi ) ){ + if( d_child_counter<(int)(getNumChildren()-1) ){ + d_child_counter++; + Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl; + getChild( d_child_counter )->reset( p, d_tgt, qi ); + }else{ + d_child_counter = -1; + } + }else{ + success = true; + } + } + }else if( d_n.getKind()==IFF ){ + //construct match based on both children + if( d_child_counter%2==0 ){ + if( getChild( 0 )->getNextMatch( p, qi ) ){ + d_child_counter++; + getChild( 1 )->reset( p, d_child_counter==1, qi ); + }else{ + if( d_child_counter==0 ){ + d_child_counter = 2; + getChild( 0 )->reset( p, !d_tgt, qi ); + }else{ + d_child_counter = -1; + } + } + } + if( d_child_counter>=0 && d_child_counter%2==1 ){ + if( getChild( 1 )->getNextMatch( p, qi ) ){ + success = true; + }else{ + d_child_counter--; + } + } + }else if( d_n.getKind()==ITE ){ + if( d_child_counter%2==0 ){ + int index1 = d_child_counter==4 ? 1 : 0; + if( getChild( index1 )->getNextMatch( p, qi ) ){ + d_child_counter++; + getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2) )->reset( p, d_tgt, qi ); + }else{ + if( d_child_counter==4 || ( d_type==typ_ite_var && d_child_counter==2 ) ){ + d_child_counter = -1; + }else{ + d_child_counter +=2; + getChild( d_child_counter==2 ? 0 : 1 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, qi ); + } + } + } + if( d_child_counter>=0 && d_child_counter%2==1 ){ + int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==1) ? 1 : 2); + if( getChild( index2 )->getNextMatch( p, qi ) ){ + success = true; + }else{ + d_child_counter--; + } + } + }else if( d_n.getKind()==FORALL ){ + if( getChild( d_child_counter )->getNextMatch( p, qi ) ){ + success = true; + }else{ + d_child_counter = -1; + } + } + } + d_wasSet = success; + Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl; + return success; + } + } + Debug("qcf-match") << " ...already finished for " << d_n << std::endl; + return false; +} + +bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) { + if( d_type==typ_eq ){ + Node n[2]; + for( unsigned i=0; i<2; i++ ){ + Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl; + n[i] = getExplanationTerm( p, qi, d_n[i], exp ); + } + Node eq = n[0].eqNode( n[1] ); + if( !d_tgt_orig ){ + eq = eq.negate(); + } + exp.push_back( eq ); + Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl; + return true; + }else if( d_type==typ_pred ){ + Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl; + Node n = getExplanationTerm( p, qi, d_n, exp ); + if( !d_tgt_orig ){ + n = n.negate(); + } + exp.push_back( n ); + Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl; + return true; + }else if( d_type==typ_formula ){ + Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl; + if( d_n.getKind()==OR || d_n.getKind()==AND ){ + if( (d_n.getKind()==AND)==d_tgt ){ + for( unsigned i=0; igetExplanation( p, qi, exp ) ){ + return false; + } + } + }else{ + return getChild( d_child_counter )->getExplanation( p, qi, exp ); + } + }else if( d_n.getKind()==IFF ){ + for( unsigned i=0; i<2; i++ ){ + if( !getChild( i )->getExplanation( p, qi, exp ) ){ + return false; + } + } + }else if( d_n.getKind()==ITE ){ + for( unsigned i=0; i<3; i++ ){ + bool isActive = ( ( i==0 && d_child_counter!=5 ) || + ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) || + ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) ); + if( isActive ){ + if( !getChild( i )->getExplanation( p, qi, exp ) ){ + return false; + } + } + } + }else{ + return false; + } + return true; + }else{ + return false; + } +} + +Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) { + Node v = qi->getCurrentExpValue( t ); + if( isHandledUfTerm( t ) ){ + for( unsigned i=0; i0 ); + bool invalidMatch; + do { + invalidMatch = false; + Debug("qcf-match-debug") << " Do matching " << d_n << " " << d_qn.size() << " " << d_qni.size() << std::endl; + if( d_qn.size()==d_qni.size()+1 ) { + int index = (int)d_qni.size(); + //initialize + TNode val; + std::map< int, int >::iterator itv = d_qni_var_num.find( index ); + if( itv!=d_qni_var_num.end() ){ + //get the representative variable this variable is equal to + int repVar = qi->getCurrentRepVar( itv->second ); + Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl; + //get the value the rep variable + //std::map< int, TNode >::iterator itm = qi->d_match.find( repVar ); + if( !qi->d_match[repVar].isNull() ){ + val = qi->d_match[repVar]; + Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl; + }else{ + //binding a variable + d_qni_bound[index] = repVar; + std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.begin(); + if( it != d_qn[index]->d_data.end() ) { + d_qni.push_back( it ); + //set the match + if( it->first.getType().isSubtypeOf( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first ) ){ + Debug("qcf-match-debug") << " Binding variable" << std::endl; + if( d_qn.size()second ); + } + }else{ + Debug("qcf-match") << " Binding variable, currently fail." << std::endl; + invalidMatch = true; + } + }else{ + Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl; + d_qn.pop_back(); + } + } + }else{ + Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl; + Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() ); + Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() ); + val = d_qni_gterm_rep[index]; + Assert( !val.isNull() ); + } + if( !val.isNull() ){ + //constrained by val + std::map< TNode, TermArgTrie >::iterator it = d_qn[index]->d_data.find( val ); + if( it!=d_qn[index]->d_data.end() ){ + Debug("qcf-match-debug") << " Match" << std::endl; + d_qni.push_back( it ); + if( d_qn.size()second ); + } + }else{ + Debug("qcf-match-debug") << " Failed to match" << std::endl; + d_qn.pop_back(); + } + } + }else{ + Assert( d_qn.size()==d_qni.size() ); + int index = d_qni.size()-1; + //increment if binding this variable + bool success = false; + std::map< int, int >::iterator itb = d_qni_bound.find( index ); + if( itb!=d_qni_bound.end() ){ + d_qni[index]++; + if( d_qni[index]!=d_qn[index]->d_data.end() ){ + success = true; + if( qi->setMatch( p, itb->second, d_qni[index]->first ) ){ + Debug("qcf-match-debug") << " Bind next variable" << std::endl; + if( d_qn.size()second ); + } + }else{ + Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl; + invalidMatch = true; + } + }else{ + qi->d_match[ itb->second ] = TNode::null(); + qi->d_match_term[ itb->second ] = TNode::null(); + Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; + } + }else{ + //TODO : if it equal to something else, also try that + } + //if not incrementing, move to next + if( !success ){ + d_qn.pop_back(); + d_qni.pop_back(); + } + } + }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch ); + if( d_qni.size()==d_qni_size ){ + //Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() ); + //Debug("qcf-match-debug") << " We matched " << d_qni[d_qni.size()-1]->second.d_children.begin()->first << std::endl; + Assert( !d_qni[d_qni.size()-1]->second.d_data.empty() ); + TNode t = d_qni[d_qni.size()-1]->second.d_data.begin()->first; + Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl; + qi->d_match_term[d_qni_var_num[0]] = t; + //set the match terms + for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ + Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl; + //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term + if( it->first>0 ){ + Assert( !qi->d_match[ it->second ].isNull() ); + Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) ); + qi->d_match_term[it->second] = t[it->first-1]; + } + //} + } + } + } + } + return !d_qn.empty(); +} + +void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) { + if( isTrace ){ + switch( typ ){ + case typ_invalid: Trace(c) << "invalid";break; + case typ_ground: Trace(c) << "ground";break; + case typ_eq: Trace(c) << "eq";break; + case typ_pred: Trace(c) << "pred";break; + case typ_formula: Trace(c) << "formula";break; + case typ_var: Trace(c) << "var";break; + case typ_ite_var: Trace(c) << "ite_var";break; + case typ_bool_var: Trace(c) << "bool_var";break; + } + }else{ + switch( typ ){ + case typ_invalid: Debug(c) << "invalid";break; + case typ_ground: Debug(c) << "ground";break; + case typ_eq: Debug(c) << "eq";break; + case typ_pred: Debug(c) << "pred";break; + case typ_formula: Debug(c) << "formula";break; + case typ_var: Debug(c) << "var";break; + case typ_ite_var: Debug(c) << "ite_var";break; + case typ_bool_var: Debug(c) << "bool_var";break; + } + } +} + +void MatchGen::setInvalid() { + d_type = typ_invalid; + d_children.clear(); +} + +bool MatchGen::isHandledBoolConnective( TNode n ) { + return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT ); +} + +bool MatchGen::isHandledUfTerm( TNode n ) { + //return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT || + // n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR_TOTAL || n.getKind()==APPLY_TESTER; + return inst::Trigger::isAtomicTriggerKind( n.getKind() ); +} + +Node MatchGen::getOperator( QuantConflictFind * p, Node n ) { + if( isHandledUfTerm( n ) ){ + return p->getTermDatabase()->getOperator( n ); + }else{ + return Node::null(); + } +} + +bool MatchGen::isHandled( TNode n ) { + if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){ + if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){ + return false; + } + for( unsigned i=0; imkConst(true); + d_false = NodeManager::currentNM()->mkConst(false); +} + +Node QuantConflictFind::mkEqNode( Node a, Node b ) { + if( a.getType().isBoolean() ){ + return a.iffNode( b ); + }else{ + return a.eqNode( b ); + } +} + +//-------------------------------------------------- registration + +void QuantConflictFind::registerQuantifier( Node q ) { + if( d_quantEngine->hasOwnership( q, this ) ){ + d_quants.push_back( q ); + d_quant_id[q] = d_quants.size(); + Trace("qcf-qregister") << "Register "; + debugPrintQuant( "qcf-qregister", q ); + Trace("qcf-qregister") << " : " << q << std::endl; + //make QcfNode structure + Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; + d_qinfo[q].initialize( q, q[1] ); + + //debug print + Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; + Trace("qcf-qregister") << " "; + debugPrintQuantBody( "qcf-qregister", q, q[1] ); + Trace("qcf-qregister") << std::endl; + if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ + Trace("qcf-qregister") << " with additional constraints : " << std::endl; + for( unsigned j=q[0].getNumChildren(); jQuantConflictFind::effort_conflict ){ + // ret = -1; + //} + }else if( n.getKind()==NOT ){ + return -evaluate( n[0] ); + }else if( n.getKind()==ITE ){ + int cev1 = evaluate( n[0] ); + int cevc[2] = { 0, 0 }; + for( unsigned i=0; i<2; i++ ){ + if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){ + cevc[i] = evaluate( n[i+1] ); + if( cev1!=0 ){ + ret = cevc[i]; + break; + }else if( cevc[i]==0 ){ + break; + } + } + } + if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){ + ret = cevc[0]; + } + }else if( n.getKind()==IFF ){ + int cev1 = evaluate( n[0] ); + if( cev1!=0 ){ + int cev2 = evaluate( n[1] ); + if( cev2!=0 ){ + ret = cev1==cev2 ? 1 : -1; + } + } + + }else{ + int ssval = 0; + if( n.getKind()==OR ){ + ssval = 1; + }else if( n.getKind()==AND ){ + ssval = -1; + } + bool isUnk = false; + for( unsigned i=0; ihasOwnership( q, this ) ){ + Trace("qcf-proc") << "QCF : assertQuantifier : "; + debugPrintQuant("qcf-proc", q); + Trace("qcf-proc") << std::endl; + d_qassert.push_back( q ); + //set the eqRegistries that this depends on to true + //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){ + // it->first->d_active.set( true ); + //} + } +} + +Node QuantConflictFind::evaluateTerm( Node n ) { + if( MatchGen::isHandledUfTerm( n ) ){ + Node f = MatchGen::getOperator( this, n ); + Node nn; + if( getEqualityEngine()->hasTerm( n ) ){ + nn = getTermDatabase()->existsTerm( f, n ); + }else{ + std::vector< TNode > args; + for( unsigned i=0; id_func_map_trie[f].existsTerm( args ); + } + if( !nn.isNull() ){ + Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; + return getRepresentative( nn ); + }else{ + Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n ) << std::endl; + return n; + } + }else if( n.getKind()==ITE ){ + int v = evaluate( n[0], false, false ); + if( v==1 ){ + return evaluateTerm( n[1] ); + }else if( v==-1 ){ + return evaluateTerm( n[2] ); + } + } + return getRepresentative( n ); +} + +/** new node */ +void QuantConflictFind::newEqClass( Node n ) { + +} + +/** merge */ +void QuantConflictFind::merge( Node a, Node b ) { + +} + +/** assert disequal */ +void QuantConflictFind::assertDisequal( Node a, Node b ) { + +} + +//-------------------------------------------------- check function + +bool QuantConflictFind::needsCheck( Theory::Effort level ) { + bool performCheck = false; + if( options::quantConflictFind() && !d_conflict ){ + if( level==Theory::EFFORT_LAST_CALL ){ + performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL; + }else if( level==Theory::EFFORT_FULL ){ + performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT; + }else if( level==Theory::EFFORT_STANDARD ){ + performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD; + } + } + return performCheck; +} + +void QuantConflictFind::reset_round( Theory::Effort level ) { + d_needs_computeRelEqr = true; +} + +/** check */ +void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { + if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){ + Trace("qcf-check") << "QCF : check : " << level << std::endl; + if( d_conflict ){ + Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl; + if( level>=Theory::EFFORT_FULL ){ + Trace("qcf-warn") << "ALREADY IN CONFLICT? " << level << std::endl; + //Assert( false ); + } + }else{ + int addedLemmas = 0; + ++(d_statistics.d_inst_rounds); + double clSet = 0; + int prevEt = 0; + if( Trace.isOn("qcf-engine") ){ + prevEt = d_statistics.d_entailment_checks.getData(); + clSet = double(clock())/double(CLOCKS_PER_SEC); + Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl; + } + computeRelevantEqr(); + + //determine order for quantified formulas + std::vector< Node > qorder; + std::map< Node, bool > qassert; + //mark which are asserted + for( unsigned i=0; id_mg->isValid() ){ + Trace("qcf-check") << "Check quantified formula "; + debugPrintQuant("qcf-check", q); + Trace("qcf-check") << " : " << q << "..." << std::endl; + + Trace("qcf-check-debug") << "Reset round..." << std::endl; + qi->reset_round( this ); + //try to make a matches making the body false + Trace("qcf-check-debug") << "Get next match..." << std::endl; + while( qi->d_mg->getNextMatch( this, qi ) ){ + Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl; + qi->debugPrintMatch("qcf-inst"); + Trace("qcf-inst") << std::endl; + std::vector< int > assigned; + if( !qi->isMatchSpurious( this ) ){ + if( qi->completeMatch( this, assigned ) ){ + std::vector< Node > terms; + qi->getMatch( terms ); + if( !qi->isTConstraintSpurious( this, terms ) ){ + if( Debug.isOn("qcf-check-inst") ){ + //if( e==effort_conflict ){ + Node inst = d_quantEngine->getInstantiation( q, terms ); + Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; + Assert( evaluate( inst )!=1 ); + Assert( evaluate( inst )==-1 || e>effort_conflict ); + //} + } + if( d_quantEngine->addInstantiation( q, terms, false ) ){ + Trace("qcf-check") << " ... Added instantiation" << std::endl; + Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; + qi->debugPrintMatch("qcf-inst"); + Trace("qcf-inst") << std::endl; + ++addedLemmas; + if( e==effort_conflict ){ + d_quant_order.insert( d_quant_order.begin(), q ); + d_conflict.set( true ); + ++(d_statistics.d_conflict_inst); + break; + }else if( e==effort_prop_eq ){ + ++(d_statistics.d_prop_inst); + } + }else{ + Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; + //Assert( false ); + } + } + //clean up assigned + qi->revertMatch( assigned ); + d_tempCache.clear(); + }else{ + Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl; + } + }else{ + Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl; + } + } + if( d_conflict ){ + break; + } + } + } + if( addedLemmas>0 ){ + break; + } + } + if( Trace.isOn("qcf-engine") ){ + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet); + if( addedLemmas>0 ){ + Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) ); + Trace("qcf-engine") << ", addedLemmas = " << addedLemmas; + } + Trace("qcf-engine") << std::endl; + int currEt = d_statistics.d_entailment_checks.getData(); + if( currEt!=prevEt ){ + Trace("qcf-engine") << " Entailment checks = " << ( currEt - prevEt ) << std::endl; + } + } + Trace("qcf-check2") << "QCF : finished check : " << level << std::endl; + } + } +} + +void QuantConflictFind::computeRelevantEqr() { + if( d_needs_computeRelEqr ){ + d_needs_computeRelEqr = false; + Trace("qcf-check") << "Compute relevant equalities..." << std::endl; + //d_uf_terms.clear(); + //d_eqc_uf_terms.clear(); + d_eqcs.clear(); + d_model_basis.clear(); + //d_arg_reps.clear(); + //double clSet = 0; + //if( Trace.isOn("qcf-opt") ){ + // clSet = double(clock())/double(CLOCKS_PER_SEC); + //} + + //long nTermst = 0; + //long nTerms = 0; + //long nEqc = 0; + + //which nodes are irrelevant for disequality matches + std::map< TNode, bool > irrelevant_dnode; + //now, store matches + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); + while( !eqcs_i.isFinished() ){ + //nEqc++; + Node r = (*eqcs_i); + if( getTermDatabase()->hasTermCurrent( r ) ){ + TypeNode rtn = r.getType(); + if( options::qcfMode()==QCF_MC ){ + std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn ); + if( itt==d_eqcs.end() ){ + Node mb = getTermDatabase()->getModelBasisTerm( rtn ); + if( !getEqualityEngine()->hasTerm( mb ) ){ + Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl; + Assert( false ); + } + Node mbr = getRepresentative( mb ); + if( mbr!=r ){ + d_eqcs[rtn].push_back( mbr ); + } + d_eqcs[rtn].push_back( r ); + d_model_basis[rtn] = mb; + }else{ + itt->second.push_back( r ); + } + }else{ + d_eqcs[rtn].push_back( r ); + } + } + ++eqcs_i; + } + /* + if( Trace.isOn("qcf-opt") ){ + double clSet2 = double(clock())/double(CLOCKS_PER_SEC); + Trace("qcf-opt") << "Compute rel eqc : " << std::endl; + Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl; + Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl; + Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl; + } + */ + } +} + + +//-------------------------------------------------- debugging + + +void QuantConflictFind::debugPrint( const char * c ) { + //print the equivalance classes + Trace(c) << "----------EQ classes" << std::endl; + eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); + while( !eqcs_i.isFinished() ){ + Node n = (*eqcs_i); + //if( !n.getType().isInteger() ){ + Trace(c) << " - " << n << " : {"; + eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() ); + bool pr = false; + while( !eqc_i.isFinished() ){ + Node nn = (*eqc_i); + if( nn.getKind()!=EQUAL && nn!=n ){ + Trace(c) << (pr ? "," : "" ) << " " << nn; + pr = true; + } + ++eqc_i; + } + Trace(c) << (pr ? " " : "" ) << "}" << std::endl; + /* + EqcInfo * eqcn = getEqcInfo( n, false ); + if( eqcn ){ + Trace(c) << " DEQ : {"; + pr = false; + for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){ + if( (*it).second ){ + Trace(c) << (pr ? "," : "" ) << " " << (*it).first; + pr = true; + } + } + Trace(c) << (pr ? " " : "" ) << "}" << std::endl; + } + //} + */ + ++eqcs_i; + } +} + +void QuantConflictFind::debugPrintQuant( const char * c, Node q ) { + Trace(c) << "Q" << d_quant_id[q]; +} + +void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) { + if( n.getNumChildren()==0 ){ + Trace(c) << n; + }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){ + Trace(c) << "?x" << d_qinfo[q].d_var_num[n]; + }else{ + Trace(c) << "("; + if( n.getKind()==APPLY_UF ){ + Trace(c) << n.getOperator(); + }else{ + Trace(c) << n.getKind(); + } + for( unsigned i=0; i::iterator it = d_zero.find( k ); + if( it==d_zero.end() ){ + Node nn; + if( k==PLUS ){ + nn = NodeManager::currentNM()->mkConst( Rational(0) ); + } + d_zero[k] = nn; + return nn; + }else{ + return it->second; + } +} + + +} diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index 829b67777..d2a982781 100644 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -1,255 +1,255 @@ -/********************* */ -/*! \file quant_conflict_find.h - ** \verbatim - ** Original author: Andrew Reynolds - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 project. - ** Copyright (c) 2009-2014 New York University and The University of Iowa - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief quantifiers conflict find class - **/ - -#include "cvc4_private.h" - -#ifndef QUANT_CONFLICT_FIND -#define QUANT_CONFLICT_FIND - -#include "context/cdhashmap.h" -#include "context/cdchunk_list.h" -#include "theory/quantifiers_engine.h" -#include "theory/quantifiers/term_database.h" - -namespace CVC4 { -namespace theory { -namespace quantifiers { - -class QuantConflictFind; -class QuantInfo; - -//match generator -class MatchGen { - friend class QuantInfo; -private: - //current children information - int d_child_counter; - //children of this object - std::vector< int > d_children_order; - unsigned getNumChildren() { return d_children.size(); } - MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; } - //MatchGen * getChild( int i ) { return &d_children[i]; } - //current matching information - std::vector< TermArgTrie * > d_qn; - std::vector< std::map< TNode, TermArgTrie >::iterator > d_qni; - bool doMatching( QuantConflictFind * p, QuantInfo * qi ); - //for matching : each index is either a variable or a ground term - unsigned d_qni_size; - std::map< int, int > d_qni_var_num; - std::map< int, TNode > d_qni_gterm; - std::map< int, TNode > d_qni_gterm_rep; - std::map< int, int > d_qni_bound; - std::vector< int > d_qni_bound_except; - std::map< int, TNode > d_qni_bound_cons; - std::map< int, int > d_qni_bound_cons_var; - std::map< int, int >::iterator d_binding_it; - //std::vector< int > d_independent; - bool d_matched_basis; - bool d_binding; - //int getVarBindingVar(); - std::map< int, Node > d_ground_eval; - //determine variable order - void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ); - void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ); -public: - //type of the match generator - enum { - typ_invalid, - typ_ground, - typ_pred, - typ_eq, - typ_formula, - typ_var, - typ_ite_var, - typ_bool_var, - typ_tconstraint, - typ_tsym, - }; - void debugPrintType( const char * c, short typ, bool isTrace = false ); -public: - MatchGen() : d_type( typ_invalid ){} - MatchGen( QuantInfo * qi, Node n, bool isVar = false ); - bool d_tgt; - bool d_tgt_orig; - bool d_wasSet; - Node d_n; - std::vector< MatchGen > d_children; - short d_type; - bool d_type_not; - void reset_round( QuantConflictFind * p ); - void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ); - bool getNextMatch( QuantConflictFind * p, QuantInfo * qi ); - bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ); - Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ); - bool isValid() { return d_type!=typ_invalid; } - void setInvalid(); - - // is this term treated as UF application? - static bool isHandledBoolConnective( TNode n ); - static bool isHandledUfTerm( TNode n ); - static Node getOperator( QuantConflictFind * p, Node n ); - //can this node be handled by the algorithm - static bool isHandled( TNode n ); -}; - -//info for quantifiers -class QuantInfo { -private: - void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false ); - void flatten( Node n, bool beneathQuant ); -private: //for completing match - std::vector< int > d_unassigned; - std::vector< TypeNode > d_unassigned_tn; - int d_unassigned_nvar; - int d_una_index; - std::vector< int > d_una_eqc_count; -public: - QuantInfo() : d_mg( NULL ) {} - ~QuantInfo() { delete d_mg; } - std::vector< TNode > d_vars; - std::vector< TypeNode > d_var_types; - std::map< TNode, int > d_var_num; - std::vector< int > d_tsym_vars; - std::map< TNode, bool > d_inMatchConstraint; - std::map< int, std::vector< Node > > d_var_constraint[2]; - int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; } - bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); } - int getNumVars() { return (int)d_vars.size(); } - TNode getVar( int i ) { return d_vars[i]; } - - MatchGen * d_mg; - Node d_q; - std::map< int, MatchGen * > d_var_mg; - void reset_round( QuantConflictFind * p ); -public: - //initialize - void initialize( Node q, Node qn ); - //current constraints - std::vector< TNode > d_match; - std::vector< TNode > d_match_term; - std::map< int, std::map< TNode, int > > d_curr_var_deq; - std::map< Node, bool > d_tconstraints; - int getCurrentRepVar( int v ); - TNode getCurrentValue( TNode n ); - TNode getCurrentExpValue( TNode n ); - bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); - int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); - int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); - bool setMatch( QuantConflictFind * p, int v, TNode n ); - bool isMatchSpurious( QuantConflictFind * p ); - bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); - bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); - bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false ); - void revertMatch( std::vector< int >& assigned ); - void debugPrintMatch( const char * c ); - bool isConstrainedVar( int v ); -public: - void getMatch( std::vector< Node >& terms ); -}; - -class QuantConflictFind : public QuantifiersModule -{ - friend class MatchGen; - friend class QuantInfo; - typedef context::CDChunkList NodeList; - typedef context::CDHashMap NodeBoolMap; -private: - context::CDO< bool > d_conflict; - std::vector< Node > d_quant_order; - std::map< Kind, Node > d_zero; - //for storing nodes created during t-constraint solving (prevents memory leaks) - std::vector< Node > d_tempCache; -private: - std::map< Node, Node > d_op_node; - int d_fid_count; - std::map< Node, int > d_fid; - Node mkEqNode( Node a, Node b ); -public: //for ground terms - Node d_true; - Node d_false; - TNode getZero( Kind k ); -private: - Node evaluateTerm( Node n ); - int evaluate( Node n, bool pref = false, bool hasPref = false ); -private: - //currently asserted quantifiers - NodeList d_qassert; - std::map< Node, QuantInfo > d_qinfo; -private: //for equivalence classes - // type -> list(eqc) - std::map< TypeNode, std::vector< TNode > > d_eqcs; - std::map< TypeNode, Node > d_model_basis; -public: - enum { - effort_conflict, - effort_prop_eq, - effort_mc, - }; - short d_effort; - void setEffort( int e ) { d_effort = e; } - static short getMaxQcfEffort(); - bool areMatchEqual( TNode n1, TNode n2 ); - bool areMatchDisequal( TNode n1, TNode n2 ); -public: - QuantConflictFind( QuantifiersEngine * qe, context::Context* c ); - ~QuantConflictFind() throw() {} - /** register quantifier */ - void registerQuantifier( Node q ); -public: - /** assert quantifier */ - void assertNode( Node q ); - /** new node */ - void newEqClass( Node n ); - /** merge */ - void merge( Node a, Node b ); - /** assert disequal */ - void assertDisequal( Node a, Node b ); - /** needs check */ - bool needsCheck( Theory::Effort level ); - /** reset round */ - void reset_round( Theory::Effort level ); - /** check */ - void check( Theory::Effort level, unsigned quant_e ); -private: - bool d_needs_computeRelEqr; -public: - void computeRelevantEqr(); -private: - void debugPrint( const char * c ); - //for debugging - std::vector< Node > d_quants; - std::map< Node, int > d_quant_id; - void debugPrintQuant( const char * c, Node q ); - void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true ); -public: - /** statistics class */ - class Statistics { - public: - IntStat d_inst_rounds; - IntStat d_conflict_inst; - IntStat d_prop_inst; - IntStat d_entailment_checks; - Statistics(); - ~Statistics(); - }; - Statistics d_statistics; - /** Identify this module */ - std::string identify() const { return "QcfEngine"; } -}; - -} -} -} - -#endif +/********************* */ +/*! \file quant_conflict_find.h + ** \verbatim + ** Original author: Andrew Reynolds + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 project. + ** Copyright (c) 2009-2014 New York University and The University of Iowa + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief quantifiers conflict find class + **/ + +#include "cvc4_private.h" + +#ifndef QUANT_CONFLICT_FIND +#define QUANT_CONFLICT_FIND + +#include "context/cdhashmap.h" +#include "context/cdchunk_list.h" +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/term_database.h" + +namespace CVC4 { +namespace theory { +namespace quantifiers { + +class QuantConflictFind; +class QuantInfo; + +//match generator +class MatchGen { + friend class QuantInfo; +private: + //current children information + int d_child_counter; + //children of this object + std::vector< int > d_children_order; + unsigned getNumChildren() { return d_children.size(); } + MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; } + //MatchGen * getChild( int i ) { return &d_children[i]; } + //current matching information + std::vector< TermArgTrie * > d_qn; + std::vector< std::map< TNode, TermArgTrie >::iterator > d_qni; + bool doMatching( QuantConflictFind * p, QuantInfo * qi ); + //for matching : each index is either a variable or a ground term + unsigned d_qni_size; + std::map< int, int > d_qni_var_num; + std::map< int, TNode > d_qni_gterm; + std::map< int, TNode > d_qni_gterm_rep; + std::map< int, int > d_qni_bound; + std::vector< int > d_qni_bound_except; + std::map< int, TNode > d_qni_bound_cons; + std::map< int, int > d_qni_bound_cons_var; + std::map< int, int >::iterator d_binding_it; + //std::vector< int > d_independent; + bool d_matched_basis; + bool d_binding; + //int getVarBindingVar(); + std::map< int, Node > d_ground_eval; + //determine variable order + void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ); + void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ); +public: + //type of the match generator + enum { + typ_invalid, + typ_ground, + typ_pred, + typ_eq, + typ_formula, + typ_var, + typ_ite_var, + typ_bool_var, + typ_tconstraint, + typ_tsym, + }; + void debugPrintType( const char * c, short typ, bool isTrace = false ); +public: + MatchGen() : d_type( typ_invalid ){} + MatchGen( QuantInfo * qi, Node n, bool isVar = false ); + bool d_tgt; + bool d_tgt_orig; + bool d_wasSet; + Node d_n; + std::vector< MatchGen > d_children; + short d_type; + bool d_type_not; + void reset_round( QuantConflictFind * p ); + void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ); + bool getNextMatch( QuantConflictFind * p, QuantInfo * qi ); + bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ); + Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ); + bool isValid() { return d_type!=typ_invalid; } + void setInvalid(); + + // is this term treated as UF application? + static bool isHandledBoolConnective( TNode n ); + static bool isHandledUfTerm( TNode n ); + static Node getOperator( QuantConflictFind * p, Node n ); + //can this node be handled by the algorithm + static bool isHandled( TNode n ); +}; + +//info for quantifiers +class QuantInfo { +private: + void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false ); + void flatten( Node n, bool beneathQuant ); +private: //for completing match + std::vector< int > d_unassigned; + std::vector< TypeNode > d_unassigned_tn; + int d_unassigned_nvar; + int d_una_index; + std::vector< int > d_una_eqc_count; +public: + QuantInfo() : d_mg( NULL ) {} + ~QuantInfo() { delete d_mg; } + std::vector< TNode > d_vars; + std::vector< TypeNode > d_var_types; + std::map< TNode, int > d_var_num; + std::vector< int > d_tsym_vars; + std::map< TNode, bool > d_inMatchConstraint; + std::map< int, std::vector< Node > > d_var_constraint[2]; + int getVarNum( TNode v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; } + bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); } + int getNumVars() { return (int)d_vars.size(); } + TNode getVar( int i ) { return d_vars[i]; } + + MatchGen * d_mg; + Node d_q; + std::map< int, MatchGen * > d_var_mg; + void reset_round( QuantConflictFind * p ); +public: + //initialize + void initialize( Node q, Node qn ); + //current constraints + std::vector< TNode > d_match; + std::vector< TNode > d_match_term; + std::map< int, std::map< TNode, int > > d_curr_var_deq; + std::map< Node, bool > d_tconstraints; + int getCurrentRepVar( int v ); + TNode getCurrentValue( TNode n ); + TNode getCurrentExpValue( TNode n ); + bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); + int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); + int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); + bool setMatch( QuantConflictFind * p, int v, TNode n ); + bool isMatchSpurious( QuantConflictFind * p ); + bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); + bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); + bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false ); + void revertMatch( std::vector< int >& assigned ); + void debugPrintMatch( const char * c ); + bool isConstrainedVar( int v ); +public: + void getMatch( std::vector< Node >& terms ); +}; + +class QuantConflictFind : public QuantifiersModule +{ + friend class MatchGen; + friend class QuantInfo; + typedef context::CDChunkList NodeList; + typedef context::CDHashMap NodeBoolMap; +private: + context::CDO< bool > d_conflict; + std::vector< Node > d_quant_order; + std::map< Kind, Node > d_zero; + //for storing nodes created during t-constraint solving (prevents memory leaks) + std::vector< Node > d_tempCache; +private: + std::map< Node, Node > d_op_node; + int d_fid_count; + std::map< Node, int > d_fid; + Node mkEqNode( Node a, Node b ); +public: //for ground terms + Node d_true; + Node d_false; + TNode getZero( Kind k ); +private: + Node evaluateTerm( Node n ); + int evaluate( Node n, bool pref = false, bool hasPref = false ); +private: + //currently asserted quantifiers + NodeList d_qassert; + std::map< Node, QuantInfo > d_qinfo; +private: //for equivalence classes + // type -> list(eqc) + std::map< TypeNode, std::vector< TNode > > d_eqcs; + std::map< TypeNode, Node > d_model_basis; +public: + enum { + effort_conflict, + effort_prop_eq, + effort_mc, + }; + short d_effort; + void setEffort( int e ) { d_effort = e; } + static short getMaxQcfEffort(); + bool areMatchEqual( TNode n1, TNode n2 ); + bool areMatchDisequal( TNode n1, TNode n2 ); +public: + QuantConflictFind( QuantifiersEngine * qe, context::Context* c ); + ~QuantConflictFind() throw() {} + /** register quantifier */ + void registerQuantifier( Node q ); +public: + /** assert quantifier */ + void assertNode( Node q ); + /** new node */ + void newEqClass( Node n ); + /** merge */ + void merge( Node a, Node b ); + /** assert disequal */ + void assertDisequal( Node a, Node b ); + /** needs check */ + bool needsCheck( Theory::Effort level ); + /** reset round */ + void reset_round( Theory::Effort level ); + /** check */ + void check( Theory::Effort level, unsigned quant_e ); +private: + bool d_needs_computeRelEqr; +public: + void computeRelevantEqr(); +private: + void debugPrint( const char * c ); + //for debugging + std::vector< Node > d_quants; + std::map< Node, int > d_quant_id; + void debugPrintQuant( const char * c, Node q ); + void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true ); +public: + /** statistics class */ + class Statistics { + public: + IntStat d_inst_rounds; + IntStat d_conflict_inst; + IntStat d_prop_inst; + IntStat d_entailment_checks; + Statistics(); + ~Statistics(); + }; + Statistics d_statistics; + /** Identify this module */ + std::string identify() const { return "QcfEngine"; } +}; + +} +} +} + +#endif diff --git a/test/regress/regress0/fmf/fc-pigeonhole19.smt2 b/test/regress/regress0/fmf/fc-pigeonhole19.smt2 index 15c36682c..f145013d8 100644 --- a/test/regress/regress0/fmf/fc-pigeonhole19.smt2 +++ b/test/regress/regress0/fmf/fc-pigeonhole19.smt2 @@ -1,20 +1,20 @@ -(set-logic UFC) -(set-info :status unsat) - -(declare-sort P 0) -(declare-sort H 0) - -(declare-fun p () P) -(declare-fun h () H) - -; pigeonhole using native cardinality constraints -(assert (fmf.card p 19)) -(assert (not (fmf.card p 18))) -(assert (fmf.card h 18)) -(assert (not (fmf.card h 17))) - -; each pigeon has different holes -(declare-fun f (P) H) -(assert (forall ((p1 P) (p2 P)) (=> (not (= p1 p2)) (not (= (f p1) (f p2)))))) - +(set-logic UFC) +(set-info :status unsat) + +(declare-sort P 0) +(declare-sort H 0) + +(declare-fun p () P) +(declare-fun h () H) + +; pigeonhole using native cardinality constraints +(assert (fmf.card p 19)) +(assert (not (fmf.card p 18))) +(assert (fmf.card h 18)) +(assert (not (fmf.card h 17))) + +; each pigeon has different holes +(declare-fun f (P) H) +(assert (forall ((p1 P) (p2 P)) (=> (not (= p1 p2)) (not (= (f p1) (f p2)))))) + (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/fmf/fc-unsat-pent.smt2 b/test/regress/regress0/fmf/fc-unsat-pent.smt2 index f1721cb04..2d4000e6e 100644 --- a/test/regress/regress0/fmf/fc-unsat-pent.smt2 +++ b/test/regress/regress0/fmf/fc-unsat-pent.smt2 @@ -1,20 +1,20 @@ -(set-logic QF_UFC) -(set-info :status unsat) - -(declare-sort U 0) - -(declare-fun a () U) -(declare-fun b () U) -(declare-fun c () U) -(declare-fun d () U) -(declare-fun e () U) - -(assert (not (= a b))) -(assert (not (= b c))) -(assert (not (= c d))) -(assert (not (= d e))) -(assert (not (= e a))) - -(assert (fmf.card c 2)) - +(set-logic QF_UFC) +(set-info :status unsat) + +(declare-sort U 0) + +(declare-fun a () U) +(declare-fun b () U) +(declare-fun c () U) +(declare-fun d () U) +(declare-fun e () U) + +(assert (not (= a b))) +(assert (not (= b c))) +(assert (not (= c d))) +(assert (not (= d e))) +(assert (not (= e a))) + +(assert (fmf.card c 2)) + (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 b/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 index d946974ed..0d438f718 100644 --- a/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 +++ b/test/regress/regress0/fmf/fc-unsat-tot-2.smt2 @@ -1,14 +1,14 @@ -(set-logic UFC) -(set-info :status unsat) - -(declare-sort U 0) - -(declare-fun a () U) -(declare-fun b () U) -(declare-fun c () U) - -(assert (not (fmf.card a 2))) - -(assert (forall ((x U)) (or (= x a) (= x b)))) - +(set-logic UFC) +(set-info :status unsat) + +(declare-sort U 0) + +(declare-fun a () U) +(declare-fun b () U) +(declare-fun c () U) + +(assert (not (fmf.card a 2))) + +(assert (forall ((x U)) (or (= x a) (= x b)))) + (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/quantifiers/simp-typ-test.smt2 b/test/regress/regress0/quantifiers/simp-typ-test.smt2 index 366559b9d..380a66aac 100644 --- a/test/regress/regress0/quantifiers/simp-typ-test.smt2 +++ b/test/regress/regress0/quantifiers/simp-typ-test.smt2 @@ -1,7 +1,7 @@ -(set-logic UFLIRA) -(set-info :status unsat) -; ensure that E-matching matches on sub-types -(declare-fun P (Real) Bool) -(assert (forall ((x Real)) (P x))) -(assert (not (P 5))) +(set-logic UFLIRA) +(set-info :status unsat) +; ensure that E-matching matches on sub-types +(declare-fun P (Real) Bool) +(assert (forall ((x Real)) (P x))) +(assert (not (P 5))) (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/strings/at001.smt2 b/test/regress/regress0/strings/at001.smt2 index 616189d96..2ecbcc993 100644 --- a/test/regress/regress0/strings/at001.smt2 +++ b/test/regress/regress0/strings/at001.smt2 @@ -1,12 +1,12 @@ -(set-logic QF_S) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun i () Int) - -(assert (= (str.at x i) "b")) -(assert (and (>= i 4) (< i (str.len x)))) -(assert (< (str.len x) 7)) -(assert (> (str.len x) 2)) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun i () Int) + +(assert (= (str.at x i) "b")) +(assert (and (>= i 4) (< i (str.len x)))) +(assert (< (str.len x) 7)) +(assert (> (str.len x) 2)) + +(check-sat) diff --git a/test/regress/regress0/strings/bug001.smt2 b/test/regress/regress0/strings/bug001.smt2 index 49568329e..cdeebd20b 100644 --- a/test/regress/regress0/strings/bug001.smt2 +++ b/test/regress/regress0/strings/bug001.smt2 @@ -1,15 +1,15 @@ -(set-logic QF_S) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun y () String) -(declare-fun z () String) - -(assert (= "\x4a" x)) -(assert (= "\x6a" y)) - -(assert (= "\x4A" z)) - -(assert (= x z)) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun y () String) +(declare-fun z () String) + +(assert (= "\x4a" x)) +(assert (= "\x6a" y)) + +(assert (= "\x4A" z)) + +(assert (= x z)) + +(check-sat) diff --git a/test/regress/regress0/strings/bug002.smt2 b/test/regress/regress0/strings/bug002.smt2 index 15d1ea5a2..f8a481e14 100644 --- a/test/regress/regress0/strings/bug002.smt2 +++ b/test/regress/regress0/strings/bug002.smt2 @@ -1,10 +1,10 @@ -(set-logic ASLIA) -(set-info :smt-lib-version 2.0) -(set-option :strings-exp true) -(set-info :status sat) - -; regex = [\*-,\t\*-\|](.{6,}()?)+ -(define-fun strinre ((?s String)) Bool (str.in.re ?s (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.union re.nostr (re.range "*" ",") (str.to.re "\t") (re.range "*" "|") ) (re.+ (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.loop re.allchar 6 ) (re.opt (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") ) ) ) ) ) ) ) ) ) ) -(assert (not (strinre "6O\1\127\n?"))) - +(set-logic ASLIA) +(set-info :smt-lib-version 2.0) +(set-option :strings-exp true) +(set-info :status sat) + +; regex = [\*-,\t\*-\|](.{6,}()?)+ +(define-fun strinre ((?s String)) Bool (str.in.re ?s (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.union re.nostr (re.range "*" ",") (str.to.re "\t") (re.range "*" "|") ) (re.+ (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") (re.loop re.allchar 6 ) (re.opt (re.union re.nostr (re.++ (str.to.re "") (str.to.re "") ) ) ) ) ) ) ) ) ) ) +(assert (not (strinre "6O\1\127\n?"))) + (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/strings/escchar.smt2 b/test/regress/regress0/strings/escchar.smt2 index aa2afb7e4..67a184ade 100644 --- a/test/regress/regress0/strings/escchar.smt2 +++ b/test/regress/regress0/strings/escchar.smt2 @@ -1,12 +1,12 @@ -(set-logic QF_S) -(set-info :status sat) -(set-info :smt-lib-version 2.0) - -(declare-fun x () String) -(declare-const I Int) - -(assert (= x "\0\1\2\3\04\005\x06\7\8\9ABC\\\"\t\a\b")) -(assert (= I (str.len x))) - - -(check-sat) +(set-logic QF_S) +(set-info :status sat) +(set-info :smt-lib-version 2.0) + +(declare-fun x () String) +(declare-const I Int) + +(assert (= x "\0\1\2\3\04\005\x06\7\8\9ABC\\\"\t\a\b")) +(assert (= I (str.len x))) + + +(check-sat) diff --git a/test/regress/regress0/strings/escchar_25.smt2 b/test/regress/regress0/strings/escchar_25.smt2 index f48995344..af93a7ae5 100644 --- a/test/regress/regress0/strings/escchar_25.smt2 +++ b/test/regress/regress0/strings/escchar_25.smt2 @@ -1,12 +1,12 @@ -(set-logic QF_S) -(set-info :status sat) -(set-info :smt-lib-version 2.5) - -(declare-fun x () String) -(declare-const I Int) - -(assert (= x "\0\1\2\3\04\005\x06\7\8\9ABC\\""\t\a\b")) -(assert (= I (str.len x))) - - -(check-sat) +(set-logic QF_S) +(set-info :status sat) +(set-info :smt-lib-version 2.5) + +(declare-fun x () String) +(declare-const I Int) + +(assert (= x "\0\1\2\3\04\005\x06\7\8\9ABC\\""\t\a\b")) +(assert (= I (str.len x))) + + +(check-sat) diff --git a/test/regress/regress0/strings/fmf001.smt2 b/test/regress/regress0/strings/fmf001.smt2 index 05bbab586..6081c8e06 100644 --- a/test/regress/regress0/strings/fmf001.smt2 +++ b/test/regress/regress0/strings/fmf001.smt2 @@ -1,20 +1,20 @@ -(set-logic QF_S) -(set-option :strings-exp true) -(set-option :strings-fmf true) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun y () String) - -(assert (str.in.re x - (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) - )) - -(assert (str.in.re y - (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) - )) - -(assert (not (= x y))) -(assert (= (str.len x) (str.len y))) - -(check-sat) +(set-logic QF_S) +(set-option :strings-exp true) +(set-option :strings-fmf true) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun y () String) + +(assert (str.in.re x + (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) + )) + +(assert (str.in.re y + (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) + )) + +(assert (not (= x y))) +(assert (= (str.len x) (str.len y))) + +(check-sat) diff --git a/test/regress/regress0/strings/fmf002.smt2 b/test/regress/regress0/strings/fmf002.smt2 index 1d41b1085..d52dae2d2 100644 --- a/test/regress/regress0/strings/fmf002.smt2 +++ b/test/regress/regress0/strings/fmf002.smt2 @@ -1,17 +1,17 @@ -(set-logic QF_S) -(set-option :strings-exp true) -(set-option :strings-fmf true) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun y () String) -(declare-fun z () String) - -(assert (str.in.re x - (re.+ (re.range "a" "c")) - )) - -(assert (= x (str.++ y "c" z "b"))) -(assert (> (str.len z) 1)) - -(check-sat) +(set-logic QF_S) +(set-option :strings-exp true) +(set-option :strings-fmf true) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun y () String) +(declare-fun z () String) + +(assert (str.in.re x + (re.+ (re.range "a" "c")) + )) + +(assert (= x (str.++ y "c" z "b"))) +(assert (> (str.len z) 1)) + +(check-sat) diff --git a/test/regress/regress0/strings/leadingzero001.smt2 b/test/regress/regress0/strings/leadingzero001.smt2 index ae61b5f5b..2889348c1 100644 --- a/test/regress/regress0/strings/leadingzero001.smt2 +++ b/test/regress/regress0/strings/leadingzero001.smt2 @@ -1,11 +1,11 @@ -(set-logic QF_S) -(set-option :strings-exp true) -(set-info :status sat) - -(declare-fun Y () String) - -(assert (= Y "0001")) -;(assert (= (str.to.int Y) (- 1))) -(assert (= (str.to.int Y) 1)) - -(check-sat) +(set-logic QF_S) +(set-option :strings-exp true) +(set-info :status sat) + +(declare-fun Y () String) + +(assert (= Y "0001")) +;(assert (= (str.to.int Y) (- 1))) +(assert (= (str.to.int Y) 1)) + +(check-sat) diff --git a/test/regress/regress0/strings/loop008.smt2 b/test/regress/regress0/strings/loop008.smt2 index 113577e48..f84ba442b 100644 --- a/test/regress/regress0/strings/loop008.smt2 +++ b/test/regress/regress0/strings/loop008.smt2 @@ -1,10 +1,10 @@ -(set-logic QF_S) -(set-option :strings-exp true) -(set-info :status sat) - -(declare-fun x () String) - -(assert (= (str.++ x "ab") (str.++ "ba" x))) -(assert (> (str.len x) 5)) - -(check-sat) +(set-logic QF_S) +(set-option :strings-exp true) +(set-info :status sat) + +(declare-fun x () String) + +(assert (= (str.++ x "ab") (str.++ "ba" x))) +(assert (> (str.len x) 5)) + +(check-sat) diff --git a/test/regress/regress0/strings/loop009.smt2 b/test/regress/regress0/strings/loop009.smt2 index 9ccc6de6e..30fc6cebc 100644 --- a/test/regress/regress0/strings/loop009.smt2 +++ b/test/regress/regress0/strings/loop009.smt2 @@ -1,10 +1,10 @@ -(set-logic QF_S) -(set-option :strings-exp true) -(set-info :status sat) - -(declare-fun x () String) - -(assert (= (str.++ x "aa") (str.++ "aa" x))) -(assert (= (str.len x) 7)) - -(check-sat) +(set-logic QF_S) +(set-option :strings-exp true) +(set-info :status sat) + +(declare-fun x () String) + +(assert (= (str.++ x "aa") (str.++ "aa" x))) +(assert (= (str.len x) 7)) + +(check-sat) diff --git a/test/regress/regress0/strings/regexp001.smt2 b/test/regress/regress0/strings/regexp001.smt2 index 6a2044ea8..62c142d1d 100644 --- a/test/regress/regress0/strings/regexp001.smt2 +++ b/test/regress/regress0/strings/regexp001.smt2 @@ -1,13 +1,13 @@ -(set-logic QF_S) -(set-info :status sat) -(set-option :strings-exp true) - -(declare-fun x () String) - -(assert (str.in.re x - (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) - )) - -(assert (= (str.len x) 3)) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) +(set-option :strings-exp true) + +(declare-fun x () String) + +(assert (str.in.re x + (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) + )) + +(assert (= (str.len x) 3)) + +(check-sat) diff --git a/test/regress/regress0/strings/regexp002.smt2 b/test/regress/regress0/strings/regexp002.smt2 index 8c29ccb38..a8bd2187a 100644 --- a/test/regress/regress0/strings/regexp002.smt2 +++ b/test/regress/regress0/strings/regexp002.smt2 @@ -1,24 +1,24 @@ -(set-logic QF_S) -(set-info :status sat) -(set-option :strings-exp true) -; this option requires user to check whether the constraint is in the fragment -; currently we do not provide only positive membership constraint checking -; if users use this option but the constraint is not in this fragment, the result will fail -(set-option :strings-inm true) - -(declare-fun x () String) -(declare-fun y () String) - -(assert (str.in.re x - (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) - )) - -(assert (str.in.re y - (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) - )) - -(assert (not (= x y))) -(assert (= (str.len x) (str.len y))) -(assert (= (str.len y) 3)) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) +(set-option :strings-exp true) +; this option requires user to check whether the constraint is in the fragment +; currently we do not provide only positive membership constraint checking +; if users use this option but the constraint is not in this fragment, the result will fail +(set-option :strings-inm true) + +(declare-fun x () String) +(declare-fun y () String) + +(assert (str.in.re x + (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) + )) + +(assert (str.in.re y + (re.* (re.++ (re.* (str.to.re "a") ) (str.to.re "b") )) + )) + +(assert (not (= x y))) +(assert (= (str.len x) (str.len y))) +(assert (= (str.len y) 3)) + +(check-sat) diff --git a/test/regress/regress0/strings/regexp003.smt2 b/test/regress/regress0/strings/regexp003.smt2 index 601689958..7696838fe 100644 --- a/test/regress/regress0/strings/regexp003.smt2 +++ b/test/regress/regress0/strings/regexp003.smt2 @@ -1,13 +1,13 @@ -(set-logic QF_S) -(set-info :status sat) -(set-option :strings-exp true) - -(declare-const s String) - -(assert (str.in.re s (re.inter - (re.++ (str.to.re "a") (re.* (str.to.re "b")) - (re.inter (str.to.re "c") (re.* (str.to.re "c")))) - (re.++ (str.to.re "a") (re.* (str.to.re "b")) (re.* (str.to.re "c"))) - ))) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) +(set-option :strings-exp true) + +(declare-const s String) + +(assert (str.in.re s (re.inter + (re.++ (str.to.re "a") (re.* (str.to.re "b")) + (re.inter (str.to.re "c") (re.* (str.to.re "c")))) + (re.++ (str.to.re "a") (re.* (str.to.re "b")) (re.* (str.to.re "c"))) + ))) + +(check-sat) diff --git a/test/regress/regress0/strings/reloop.smt2 b/test/regress/regress0/strings/reloop.smt2 index 39b2b76b1..9915504ae 100644 --- a/test/regress/regress0/strings/reloop.smt2 +++ b/test/regress/regress0/strings/reloop.smt2 @@ -1,18 +1,18 @@ -(set-logic QF_S) -(set-option :strings-exp true) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun y () String) -(declare-fun z () String) -(declare-fun w () String) - -(assert (str.in.re x (re.loop (str.to.re "a") 5))) -(assert (str.in.re y (re.loop (str.to.re "b") 2 5))) -(assert (str.in.re z (re.loop (str.to.re "c") 5))) -(assert (> (str.len z) 7)) -(assert (str.in.re w (re.loop (str.to.re "b") 2 7))) -(assert (> (str.len w) 2)) -(assert (< (str.len w) 5)) - -(check-sat) +(set-logic QF_S) +(set-option :strings-exp true) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun y () String) +(declare-fun z () String) +(declare-fun w () String) + +(assert (str.in.re x (re.loop (str.to.re "a") 5))) +(assert (str.in.re y (re.loop (str.to.re "b") 2 5))) +(assert (str.in.re z (re.loop (str.to.re "c") 5))) +(assert (> (str.len z) 7)) +(assert (str.in.re w (re.loop (str.to.re "b") 2 7))) +(assert (> (str.len w) 2)) +(assert (< (str.len w) 5)) + +(check-sat) diff --git a/test/regress/regress0/strings/str006.smt2 b/test/regress/regress0/strings/str006.smt2 index 592ef6a7f..2bdf9b1b5 100644 --- a/test/regress/regress0/strings/str006.smt2 +++ b/test/regress/regress0/strings/str006.smt2 @@ -1,14 +1,14 @@ -(set-logic QF_S) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun y () String) -(declare-fun z () String) - -;plandowski p469 1 -(assert (= (str.++ x "ab" y) (str.++ y "ba" z))) -(assert (= z (str.++ x y))) -(assert (not (= (str.++ x "a") (str.++ "a" x)))) - -(check-sat) - +(set-logic QF_S) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun y () String) +(declare-fun z () String) + +;plandowski p469 1 +(assert (= (str.++ x "ab" y) (str.++ y "ba" z))) +(assert (= z (str.++ x y))) +(assert (not (= (str.++ x "a") (str.++ "a" x)))) + +(check-sat) + diff --git a/test/regress/regress0/strings/str007.smt2 b/test/regress/regress0/strings/str007.smt2 index 0ca2ec4c3..a7173701a 100644 --- a/test/regress/regress0/strings/str007.smt2 +++ b/test/regress/regress0/strings/str007.smt2 @@ -1,13 +1,13 @@ -(set-logic QF_S) -(set-info :status unsat) - -(declare-fun x () String) -(declare-fun y () String) - - -(assert (or (= x y) (= x y))) - -(assert (= (str.++ x "ba") (str.++ "ab" x))) -(assert (= (str.++ y "ab") (str.++ "ab" y))) - -(check-sat) +(set-logic QF_S) +(set-info :status unsat) + +(declare-fun x () String) +(declare-fun y () String) + + +(assert (or (= x y) (= x y))) + +(assert (= (str.++ x "ba") (str.++ "ab" x))) +(assert (= (str.++ y "ab") (str.++ "ab" y))) + +(check-sat) diff --git a/test/regress/regress0/strings/substr001.smt2 b/test/regress/regress0/strings/substr001.smt2 index bdfa33afb..78f3ffee7 100644 --- a/test/regress/regress0/strings/substr001.smt2 +++ b/test/regress/regress0/strings/substr001.smt2 @@ -1,16 +1,16 @@ -(set-logic QF_S) -(set-info :status sat) - -(declare-fun x () String) -(declare-fun i1 () Int) -(declare-fun i2 () Int) -(declare-fun i3 () Int) -(declare-fun i4 () Int) - -(assert (and (>= i1 0) (>= i2 0) (< (+ i1 i2) (str.len x)))) -(assert (and (>= i3 0) (>= i4 0) (< (+ i3 i4) (str.len x)))) -(assert (= "efg" (str.substr x i1 i2) ) ) -(assert (= "bef" (str.substr x i3 i4) ) ) -(assert (> (str.len x) 5)) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) + +(declare-fun x () String) +(declare-fun i1 () Int) +(declare-fun i2 () Int) +(declare-fun i3 () Int) +(declare-fun i4 () Int) + +(assert (and (>= i1 0) (>= i2 0) (< (+ i1 i2) (str.len x)))) +(assert (and (>= i3 0) (>= i4 0) (< (+ i3 i4) (str.len x)))) +(assert (= "efg" (str.substr x i1 i2) ) ) +(assert (= "bef" (str.substr x i3 i4) ) ) +(assert (> (str.len x) 5)) + +(check-sat) diff --git a/test/regress/regress0/strings/type001.smt2 b/test/regress/regress0/strings/type001.smt2 index ca93b00e5..77eabcccc 100644 --- a/test/regress/regress0/strings/type001.smt2 +++ b/test/regress/regress0/strings/type001.smt2 @@ -1,21 +1,21 @@ -(set-logic QF_S) -(set-info :status sat) -(set-option :strings-exp true) - -(declare-fun x () String) -(declare-fun y () String) -(declare-fun i () Int) -(declare-fun j () Int) -(declare-fun z () String) - -;big num test -(assert (= x (int.to.str 4785582390527685649))) -;should be "" -(assert (= y (int.to.str (- 9)))) - -;big num -(assert (= i (str.to.int "783914785582390527685649"))) -;should be -1 -(assert (= j (str.to.int "-783914785582390527685649"))) - +(set-logic QF_S) +(set-info :status sat) +(set-option :strings-exp true) + +(declare-fun x () String) +(declare-fun y () String) +(declare-fun i () Int) +(declare-fun j () Int) +(declare-fun z () String) + +;big num test +(assert (= x (int.to.str 4785582390527685649))) +;should be "" +(assert (= y (int.to.str (- 9)))) + +;big num +(assert (= i (str.to.int "783914785582390527685649"))) +;should be -1 +(assert (= j (str.to.int "-783914785582390527685649"))) + (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/strings/type002.smt2 b/test/regress/regress0/strings/type002.smt2 index cbad2226a..296057a76 100644 --- a/test/regress/regress0/strings/type002.smt2 +++ b/test/regress/regress0/strings/type002.smt2 @@ -1,18 +1,18 @@ -(set-logic QF_S) -(set-info :status sat) -(set-option :strings-exp true) - -(declare-fun x () String) -(declare-fun y () String) -(declare-fun z () String) -(declare-fun i () Int) - -(assert (>= i 420)) -(assert (= x (u16.to.str i))) -(assert (= x (str.++ y "0" z))) -(assert (not (= y ""))) -(assert (not (= z ""))) - - - +(set-logic QF_S) +(set-info :status sat) +(set-option :strings-exp true) + +(declare-fun x () String) +(declare-fun y () String) +(declare-fun z () String) +(declare-fun i () Int) + +(assert (>= i 420)) +(assert (= x (u16.to.str i))) +(assert (= x (str.++ y "0" z))) +(assert (not (= y ""))) +(assert (not (= z ""))) + + + (check-sat) \ No newline at end of file diff --git a/test/regress/regress0/strings/type003.smt2 b/test/regress/regress0/strings/type003.smt2 index b8f0ac5ae..c2d4792cc 100644 --- a/test/regress/regress0/strings/type003.smt2 +++ b/test/regress/regress0/strings/type003.smt2 @@ -1,12 +1,12 @@ -(set-logic QF_S) -(set-info :status sat) -(set-option :strings-exp true) - -(declare-fun i () Int) -(declare-fun s () String) - -(assert (< 67 (str.to.int s))) -(assert (= (str.len s) 2)) -(assert (not (= s "68"))) - -(check-sat) +(set-logic QF_S) +(set-info :status sat) +(set-option :strings-exp true) + +(declare-fun i () Int) +(declare-fun s () String) + +(assert (< 67 (str.to.int s))) +(assert (= (str.len s) 2)) +(assert (not (= s "68"))) + +(check-sat)