exprt string_constraint_generatort::add_axioms_for_last_index_of(
  const function_application_exprt &f)
{
  const function_application_exprt::argumentst &args=f.arguments();
  string_exprt str=add_axioms_for_string_expr(args[0]);
  exprt c=args[1];
  const refined_string_typet &ref_type=to_refined_string_type(str.type());
  exprt from_index;
  assert(f.type()==ref_type.get_index_type());

  if(args.size()==2)
    from_index=minus_exprt(str.length(), from_integer(1, str.length().type()));
  else if(args.size()==3)
    from_index=args[2];
  else
    assert(false);

  if(refined_string_typet::is_java_string_pointer_type(c.type()))
  {
    string_exprt sub=add_axioms_for_string_expr(c);
    return add_axioms_for_last_index_of_string(str, sub, from_index);
  }
  else
    return add_axioms_for_last_index_of(
      str, typecast_exprt(c, ref_type.get_char_type()), from_index);
}
exprt string_constraint_generatort::add_axioms_for_last_index_of(
  const string_exprt &str, const exprt &c, const exprt &from_index)
{
  const refined_string_typet &ref_type=to_refined_string_type(str.type());
  const typet &index_type=ref_type.get_index_type();
  symbol_exprt index=fresh_exist_index("last_index_of", index_type);
  symbol_exprt contains=fresh_boolean("contains_in_last_index_of");

  // We add axioms:
  // a1 : -1 <= i <= from_index
  // a2 : (i=-1 <=> !contains)
  // a3 : (contains => i <= from_index &&s[i]=c)
  // a4 : forall n. i+1 <= n < from_index +1 &&contains => s[n]!=c
  // a5 : forall m. 0 <= m < from_index +1 &&!contains => s[m]!=c

  exprt index1=from_integer(1, index_type);
  exprt minus1=from_integer(-1, index_type);
  exprt from_index_plus_one=plus_exprt(from_index, index1);
  and_exprt a1(
    binary_relation_exprt(index, ID_ge, minus1),
    binary_relation_exprt(index, ID_lt, from_index_plus_one));
  axioms.push_back(a1);

  equal_exprt a2(not_exprt(contains), equal_exprt(index, minus1));
  axioms.push_back(a2);

  implies_exprt a3(
    contains,
    and_exprt(
      binary_relation_exprt(from_index, ID_ge, index),
      equal_exprt(str[index], c)));
  axioms.push_back(a3);

  symbol_exprt n=fresh_univ_index("QA_last_index_of", index_type);
  string_constraintt a4(
    n,
    plus_exprt(index, index1),
    from_index_plus_one,
    contains,
    not_exprt(equal_exprt(str[n], c)));
  axioms.push_back(a4);

  symbol_exprt m=fresh_univ_index("QA_last_index_of", index_type);
  string_constraintt a5(
    m,
    from_index_plus_one,
    not_exprt(contains),
    not_exprt(equal_exprt(str[m], c)));
  axioms.push_back(a5);

  return index;
}
/// add axioms corresponding to the String.equalsIgnoreCase java function
/// \par parameters: function application with two string arguments
/// \return a Boolean expression
exprt string_constraint_generatort::add_axioms_for_equals_ignore_case(
  const function_application_exprt &f)
{
  assert(f.type()==bool_typet() || f.type().id()==ID_c_bool);

  symbol_exprt eq=fresh_boolean("equal_ignore_case");
  typecast_exprt tc_eq(eq, f.type());
  string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]);
  string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]);
  typet char_type=to_refined_string_type(s1.type()).get_char_type();
  exprt char_a=constant_char('a', char_type);
  exprt char_A=constant_char('A', char_type);
  exprt char_Z=constant_char('Z', char_type);
  typet index_type=s1.length().type();

  // We add axioms:
  // a1 : eq => |s1|=|s2|
  // a2 : forall qvar, 0<=qvar<|s1|,
  //  eq => char_equal_ignore_case(s1[qvar],s2[qvar]);
  // a3 : !eq => |s1|!=s2 || (0 <=witness<|s1| &&!char_equal_ignore_case)

  implies_exprt a1(eq, s1.axiom_for_has_same_length_as(s2));
  axioms.push_back(a1);

  symbol_exprt qvar=fresh_univ_index("QA_equal_ignore_case", index_type);
  exprt constr2=character_equals_ignore_case(
    s1[qvar], s2[qvar], char_a, char_A, char_Z);
  string_constraintt a2(qvar, s1.length(), eq, constr2);
  axioms.push_back(a2);

  symbol_exprt witness=fresh_exist_index(
    "witness_unequal_ignore_case", index_type);
  exprt zero=from_integer(0, witness.type());
  and_exprt bound_witness(
    binary_relation_exprt(witness, ID_lt, s1.length()),
    binary_relation_exprt(witness, ID_ge, zero));
  exprt witness_eq=character_equals_ignore_case(
    s1[witness], s2[witness], char_a, char_A, char_Z);
  not_exprt witness_diff(witness_eq);
  implies_exprt a3(
    not_exprt(eq),
    or_exprt(
      notequal_exprt(s1.length(), s2.length()),
      and_exprt(bound_witness, witness_diff)));
  axioms.push_back(a3);

  return tc_eq;
}