Как доказать количество Дафни ‹ размер

Сейчас я изучаю Дафни. Я полностью смущен леммой, и я не знаю, как ее использовать. Учебник не очень полезен. Что, если я хочу доказать count(a) <= |a|, как мне это сделать. Спасибо за помощь.

function count(a: seq<bool>): nat
ensures count(a) <= |a|;
{
   if |a| == 0 then 0 else
   (if a[0] then 1 else 0) + count(a[1..])
}

person Tony    schedule 25.02.2017    source источник


Ответы (1)


Вы уже доказали это! Вы написали нужное свойство в качестве постусловия функции, и Дафни проверяет его без нареканий. Вот и все.

Вы также можете использовать лемму, чтобы доказать свойство. Вот пример:

function count(a: seq<bool>): nat
{
  if |a| == 0 then 0 else
  (if a[0] then 1 else 0) + count(a[1..])
}

lemma CountProperty(a: seq<bool>)
  ensures count(a) <= |a|
{
}

Опять же, Дафни проверяет лемму, не предъявляя никаких претензий, так что вы ее доказали!

Неверно предполагать, что Дафни всегда будет доказывать вам что-то автоматически. Поэтому неплохо научиться писать доказательства вручную. Вот ручное доказательство этого свойства. Просто чтобы убедиться, что Дафни не пытается выполнять индукцию автоматически, я использовал директиву, чтобы отключить ее (что сделало нашу жизнь сложнее, чем обычно делала бы Дафни):

lemma {:induction false} CountProperty(a: seq<bool>)
  ensures count(a) <= |a|
{
  // Let's consider two cases, just like the definition of "count"
  // considers two cases.
  if |a| == 0 {
    // In this case, we have:
    assert count(a) == 0 && |a| == 0;
    // so the postcondition follows easily.
  } else {
    // By the definition of "count", we have:
    assert count(a) == (if a[0] then 1 else 0) + count(a[1..]);
    // We know an upper bound on the first term of the addition:
    assert (if a[0] then 1 else 0) <= 1;
    // We can also obtain an upper bound on the second term by
    // calling the lemma recursively.  We do that here:
    CountProperty(a[1..]);
    // The call we just did gives us the following property:
    assert count(a[1..]) <= |a[1..]|;
    // Putting these two upper bounds together, we have:
    assert count(a) <= 1 + |a[1..]|;
    // We're almost done.  We just need to relate |a[1..]| to |a|.
    // This is easy:
    assert |a[1..]| == |a| - 1;
    // By the last two assertions, we now have:
    assert count(a) <= 1 + |a| - 1;
    // which is the postcondition we have to prove.
  }
}

Более приятный способ написать такое доказательство — использовать проверенное вычисление, которое Дафни называет «выражением вычисления»:

lemma {:induction false} CountProperty(a: seq<bool>)
  ensures count(a) <= |a|
{
  if |a| == 0 {
    // trivial
  } else {
    calc {
      count(a);
    ==  // def. count
      (if a[0] then 1 else 0) + count(a[1..]);
    <=  // left term is bounded by 1
      1 + count(a[1..]);
    <=  { CountProperty(a[1..]); }  // induction hypothesis gives a bound for the right term
      1 + |a[1..]|;
    ==  { assert |a[1..]| == |a| - 1; }
      |a|;
    }
  }
}

Я надеюсь, что это поможет вам начать.

Программируйте безопасно,

Рустан

person Rustan Leino    schedule 28.02.2017