Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add partial string support #327

Merged
merged 13 commits into from
Nov 1, 2023
7 changes: 6 additions & 1 deletion contrib/setup-cvc5.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ if [ ! -d "$DEPS/cvc5" ]; then
make -j$NUM_CORES
cd $DIR
else
echo "$DEPS/cvc5 already exists. If you want to rebuild, please remove it manually."
# echo "$DEPS/cvc5 already exists. If you want to rebuild, please remove it manually."
cd $DEPS
cd cvc5
cd build
make -j$NUM_CORES
cd $DIR
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is what we want to do.
If the directory already exists, then this would probably mean that cvc5 is already built in it, no?

fi

if [ -f $DEPS/cvc5/build/src/libcvc5.a ] && [ -f $DEPS/cvc5/build/src/parser/libcvc5parser.a ]; then
Expand Down
4 changes: 3 additions & 1 deletion cvc5/include/cvc5_solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ class Cvc5Solver : public AbsSmtSolver

Term make_term(bool b) const override;
Term make_term(int64_t i, const Sort & sort) const override;
Term make_term(const std::string& s, bool useEscSequences, const Sort & sort) const override;
Term make_term(const std::wstring& s, const Sort & sort) const override;
Term make_term(const std::string val,
const Sort & sort,
uint64_t base = 10) const override;
Expand Down Expand Up @@ -127,7 +129,7 @@ class Cvc5Solver : public AbsSmtSolver
// getters for solver-specific objects
// for interacting with third-party cvc5-specific software
::cvc5::Solver & get_cvc5_solver() { return solver; };

protected:
::cvc5::Solver solver;

Expand Down
64 changes: 63 additions & 1 deletion cvc5/src/cvc5_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ const std::unordered_map<PrimOp, ::cvc5::Kind> primop2kind(
{ BV_To_Nat, ::cvc5::BITVECTOR_TO_NAT },
// Indexed Op
{ Int_To_BV, ::cvc5::INT_TO_BITVECTOR },
{ StrLt, ::cvc5::STRING_LT },
{ StrLeq, ::cvc5::STRING_LEQ },
{ StrLen, ::cvc5::STRING_LENGTH },
{ StrConcat, ::cvc5::STRING_CONCAT },
{ Select, ::cvc5::SELECT },
{ Store, ::cvc5::STORE },
{ Forall, ::cvc5::FORALL },
Expand Down Expand Up @@ -163,7 +167,7 @@ Term Cvc5Solver::make_term(int64_t i, const Sort & sort) const
else if (sk == REAL)
{
c = solver.mkReal(i);
}
}
else if (sk == BV)
{
// cvc5 uses unsigned integers for mkBitVector
Expand All @@ -187,6 +191,60 @@ Term Cvc5Solver::make_term(int64_t i, const Sort & sort) const
}
}

Term Cvc5Solver::make_term(const std::string& s, bool useEscSequences, const Sort & sort) const
{
try
{
SortKind sk = sort->get_sort_kind();
::cvc5::Term c;

if (sk == STRING)
{
c = solver.mkString(s, useEscSequences);
}
else
{
std::string msg = "Can't create constant with string and useEscSequences";
msg += useEscSequences;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string msg = "Can't create constant with string and useEscSequences";
msg += useEscSequences;
std::string msg = "Can't create a string constant

msg += " for sort ";
msg += sort->to_string();
throw IncorrectUsageException(msg.c_str());
}

return std::make_shared<Cvc5Term>(c);
}
catch (::cvc5::CVC5ApiException & e)
{
throw IncorrectUsageException(e.what());
}
}

Term Cvc5Solver::make_term(const std::wstring& s, const Sort & sort) const
{
try
{
SortKind sk = sort->get_sort_kind();
::cvc5::Term c;

if (sk == STRING)
{
c = solver.mkString(s);
}
else
{
std::string msg = "Can't create constant with wstring for sort ";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string msg = "Can't create constant with wstring for sort ";
std::string msg = "Can't create string constant for sort ";

msg += sort->to_string();
throw IncorrectUsageException(msg.c_str());
}

return std::make_shared<Cvc5Term>(c);
}
catch (::cvc5::CVC5ApiException & e)
{
throw IncorrectUsageException(e.what());
}
}

Term Cvc5Solver::make_term(std::string val,
const Sort & sort,
uint64_t base) const
Expand Down Expand Up @@ -478,6 +536,10 @@ Sort Cvc5Solver::make_sort(SortKind sk) const
{
return std::make_shared<Cvc5Sort>(solver.getRealSort());
}
else if (sk == STRING)
{
return std::make_shared<Cvc5Sort>(solver.getStringSort());
}
else
{
std::string msg("Can't create sort with sort constructor ");
Expand Down
4 changes: 4 additions & 0 deletions cvc5/src/cvc5_sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ SortKind Cvc5Sort::get_sort_kind() const
{
return REAL;
}
else if (sort.isString())
{
return STRING;
}
else if (sort.isArray())
{
return ARRAY;
Expand Down
6 changes: 6 additions & 0 deletions cvc5/src/cvc5_term.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const std::unordered_map<::cvc5::Kind, PrimOp> kind2primop(
{ ::cvc5::NEG, Negate },
{ ::cvc5::MULT, Mult },
{ ::cvc5::DIVISION, Div },
{ ::cvc5::INTS_DIVISION, IntDiv },
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder -- integer division is already tested, including with cvc5:

Term div = s->make_term(IntDiv, five, two);

How come we need to add it now?

{ ::cvc5::LT, Lt },
{ ::cvc5::LEQ, Le },
{ ::cvc5::GT, Gt },
Expand Down Expand Up @@ -104,6 +105,11 @@ const std::unordered_map<::cvc5::Kind, PrimOp> kind2primop(
{ ::cvc5::BITVECTOR_ROTATE_RIGHT, Rotate_Right },
// Conversion
{ ::cvc5::BITVECTOR_TO_NAT, BV_To_Nat },
// String Op
{ ::cvc5::STRING_LT, StrLt },
{ ::cvc5::STRING_LEQ, StrLeq },
{ ::cvc5::STRING_LENGTH, StrLen },
{ ::cvc5::STRING_CONCAT, StrConcat },
// Indexed Op
{ ::cvc5::INT_TO_BITVECTOR, Int_To_BV },
{ ::cvc5::SELECT, Select },
Expand Down
5 changes: 5 additions & 0 deletions include/generic_solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ class GenericSolver : public AbsSmtSolver
*/
Term make_value(bool b) const;
Term make_value(int64_t i, const Sort & sort) const;
Term make_term(const std::string& s, bool useEscSequences, const Sort & sort) const override;
Term make_term(const std::wstring& s, const Sort & sort) const override;
Term make_value(const std::string& s, bool useEscSequences, const Sort & sort) const;
Term make_value(const std::wstring& s, const Sort & sort) const;

Term make_value(const std::string val,
const Sort & sort,
uint64_t base = 10) const;
Expand Down
2 changes: 2 additions & 0 deletions include/logging_solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class LoggingSolver : public AbsSmtSolver

Term make_term(bool b) const override;
Term make_term(int64_t i, const Sort & sort) const override;
Term make_term(const std::string& s, bool useEscSequences, const Sort & sort) const override;
Term make_term(const std::wstring& s, const Sort & sort) const override;
Term make_term(const std::string val,
const Sort & sort,
uint64_t base = 10) const override;
Expand Down
5 changes: 5 additions & 0 deletions include/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ enum PrimOp
// BitVector Conversion
BV_To_Nat,
Int_To_BV,
//Strings
ntsis marked this conversation as resolved.
Show resolved Hide resolved
StrLt,
StrLeq,
StrLen,
StrConcat,
/* Array Theory */
Select,
Store,
Expand Down
3 changes: 3 additions & 0 deletions include/printing_solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ class PrintingSolver : public AbsSmtSolver

Term make_term(bool b) const override;
Term make_term(int64_t i, const Sort & sort) const override;
Term make_term(const std::string& s, bool useEscSequences, const Sort & sort) const override;
Term make_term(const std::wstring& s, const Sort & sort) const override;

Term make_term(const std::string val,
const Sort & sort,
uint64_t base = 10) const override;
Expand Down
6 changes: 6 additions & 0 deletions include/smtlibparser_maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ const std::unordered_map<std::string, std::unordered_map<std::string, PrimOp>>
{ "repeat", Repeat },
{ "rotate_left", Rotate_Left },
{ "rotate_right", Rotate_Right } } },
// Strings
{ "STRING",
{ { "str.<", StrLt },
{ "str.<=", StrLeq},
{ "str.len", StrLen},
{ "str.++", StrConcat} } },
// ArraysEx
{ "A",
{
Expand Down
22 changes: 22 additions & 0 deletions include/solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,28 @@ class AbsSmtSolver
*/
virtual Term make_term(int64_t i, const Sort & sort) const = 0;

/* Make a string value term
* @param s is the value
* @param useEscSequences is the useEscSequences in String constructor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is not very clear. What is the string constructor? And what does useEscSequences mean? It might be the case that this documentation line is too specific to cvc5, while it should be more general.

* @param sort the sort to create
* @return a value term with Sort sort and value s
*/
virtual Term make_term(const std::string& s, bool useEscSequences, const Sort & sort) const{
yoni206 marked this conversation as resolved.
Show resolved Hide resolved
yoni206 marked this conversation as resolved.
Show resolved Hide resolved
throw NotImplementedException("Strings not supported for this solver.");

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

}

/* Make a string value term
* @param s is the value
* @param sort the sort to create
* @return a value term with Sort sort and value s
*/
virtual Term make_term(const std::wstring& s, const Sort & sort) const{
yoni206 marked this conversation as resolved.
Show resolved Hide resolved
throw NotImplementedException("Strings not supported for this solver.");

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

}


/* Make a bit-vector, int, real or (in the future) string value term
* @param val the numeric value as a string, or a string value
* @param sort the sort to create
Expand Down
1 change: 1 addition & 0 deletions include/sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ enum SortKind
BV,
INT,
REAL,
STRING,
FUNCTION,
UNINTERPRETED,
// an uninterpreted sort constructor (has non-zero arity and takes subsort
Expand Down
4 changes: 4 additions & 0 deletions include/sort_inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ bool real_sorts(const SortVec & sorts);

bool int_sorts(const SortVec & sorts);

bool string_sorts(const SortVec & sorts);

bool arithmetic_sorts(const SortVec & sorts);

bool array_sorts(const SortVec & sorts);
Expand All @@ -191,6 +193,8 @@ Sort real_sort(Op op, const AbsSmtSolver * solver, const SortVec & sorts);

Sort int_sort(Op op, const AbsSmtSolver * solver, const SortVec & sorts);

Sort string_sort(Op op, const AbsSmtSolver * solver, const SortVec & sorts);

Sort ite_sort(Op op, const AbsSmtSolver * solver, const SortVec & sorts);

Sort extract_sort(Op op, const AbsSmtSolver * solver, const SortVec & sorts);
Expand Down
30 changes: 30 additions & 0 deletions src/generic_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,36 @@ Term GenericSolver::make_value(int64_t i, const Sort & sort) const
}
}

Term GenericSolver::make_term(const std::string& s, bool useEscSequences, const Sort & sort) const
{
Term value_term = make_value(s, useEscSequences, sort);
return store_term(value_term);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

Term GenericSolver::make_term(const std::wstring& s, const Sort & sort) const
{
Term value_term = make_value(s, sort);
return store_term(value_term);
}

Term GenericSolver::make_value(const std::string& s, bool useEscSequences, const Sort & sort) const
{
SortKind sk = sort->get_sort_kind();
assert(sk == STRING);
string repr;
repr = std::to_string(s);
Term term = std::make_shared<GenericTerm>(sort, Op(), TermVec{}, repr); //figure out how to handle useEscSequences
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this figured out yet? :)
If not -- what exactly is the issue?
If so, the comment can be removed.

return term;
}
Term GenericSolver::make_value(const std::wstring& s, const Sort & sort) const
{
SortKind sk = sort->get_sort_kind();
assert(sk == STRING);
string repr;
repr = std::to_string(s);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will that always work? Is it always possible to convert a wstring to a string?

Term term = std::make_shared<GenericTerm>(sort, Op(), TermVec{}, repr);
return term;
}

Term GenericSolver::make_term(const string val,
const Sort & sort,
uint64_t base) const
Expand Down
8 changes: 5 additions & 3 deletions src/generic_sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Sort make_uninterpreted_generic_sort(Sort sort_cons,

Sort make_generic_sort(SortKind sk)
{
if (sk != BOOL && sk != INT && sk != REAL)
if (sk != BOOL && sk != INT && sk != REAL && sk!= STRING)
{
throw IncorrectUsageException("Can't create sort from " + to_string(sk));
}
Expand Down Expand Up @@ -217,7 +217,8 @@ bool GenericSort::compare(const Sort & s) const
{
case BOOL:
case INT:
case REAL: { return true;
case REAL:
case STRING: { return true;
}
case BV: { return get_width() == s->get_width();
}
Expand Down Expand Up @@ -279,7 +280,8 @@ const std::unordered_map<SortKind, std::string> sortkind2smtlib(
{ { ARRAY, "Array" },
{ BOOL, "Bool" },
{ INT, "Int" },
{ REAL, "Real" }});
{ REAL, "Real" },
{ STRING, "String" }});

std::string to_smtlib(SortKind sk)
{
Expand Down
40 changes: 40 additions & 0 deletions src/logging_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,46 @@ Term LoggingSolver::make_term(int64_t i, const Sort & sort) const
return res;
}


Term LoggingSolver::make_term(const std::string& s, bool useEscSequences, const Sort & sort) const
{
shared_ptr<LoggingSort> lsort = static_pointer_cast<LoggingSort>(sort);
Term wrapped_res = wrapped_solver->make_term(s, useEscSequences, lsort->wrapped_sort);
Term res = std::make_shared<LoggingTerm>(
wrapped_res, sort, Op(), TermVec{}, next_term_id);

// check hash table
// lookup modifies term in place and returns true if it's a known term
// i.e. returns existing term and destroying the unnecessary new one
if (!hashtable->lookup(res))
{
// this is the first time this term was created
hashtable->insert(res);
next_term_id++;
}

return res;
}
Term LoggingSolver::make_term(const std::wstring& s, const Sort & sort) const{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Term LoggingSolver::make_term(const std::wstring& s, const Sort & sort) const{
Term LoggingSolver::make_term(const std::wstring& s, const Sort & sort) const{

shared_ptr<LoggingSort> lsort = static_pointer_cast<LoggingSort>(sort);
Term wrapped_res = wrapped_solver->make_term(s, lsort->wrapped_sort);
Term res = std::make_shared<LoggingTerm>(
wrapped_res, sort, Op(), TermVec{}, next_term_id);

// check hash table
// lookup modifies term in place and returns true if it's a known term
// i.e. returns existing term and destroying the unnecessary new one
if (!hashtable->lookup(res))
{
// this is the first time this term was created
hashtable->insert(res);
next_term_id++;
}

return res;
}


Term LoggingSolver::make_term(const string name,
const Sort & sort,
uint64_t base) const
Expand Down
Loading