Производительность Z3 с нелинейной арифметикой

Мы сталкиваемся с проблемами производительности, поскольку я считаю, что Z3 является частью нелинейной арифметики. Вот простой конкретный пример Boogie, который при проверке с Z3 (версия 4.1) занимает много времени (порядка 3 минут) для завершения.

const D: int;
function f(n: int) returns (int) { n * D }

procedure test() returns ()
{
  var a, b, c: int;
  var M: [int]int;
  var t: int;

  assume 0 < a && 1000 * a < f(1);
  assume 0 < c && 1000 * c < f(1);
  assume f(100) * b == a * c;

  assert M[t] > 0;
}

Кажется, что проблема вызвана взаимодействием функций, допущением диапазона целочисленных переменных, а также умножением (неизвестных) целочисленных значений. Утверждение в конце не должно быть доказуемым. Вместо быстрого отказа, кажется, что у Z3 есть способы как-то создать множество терминов, так как его потребление памяти довольно быстро увеличивается до 300 МБ, и в этот момент он сдается.

Мне интересно, является ли это ошибкой или возможно ли улучшить эвристику, когда Z3 должен остановить поиск в определенном направлении, в котором он в настоящее время пытается решить проблему.

Одна интересная вещь заключается в том, что встраивание функции с помощью

function {:inline} f(n: int) returns (int) { n * D }

заставляет проверку прекратить очень быстро.

Предыстория: это минимальный тестовый пример для проблемы, которую мы видим в нашей чаше верификатора. Там программы Boogie становятся намного длиннее, возможно, с несколькими предположениями подобного рода. Часто проверка не заканчивается вообще.

Есть идеи?

Ответы на вопрос(1)

Ваш ответ на вопрос