Логика и верификация: дайте пример задачи верификации программы с использованием инвариантов цикла и предикатов безопасности; опишите процесс построения инварианта и доказательства корректности
Задача (пример). Требуется по неотрицательному целому aaa и целому положительному делителю bbb вычислить целые частное qqq и остаток rrr, такие что a=q⋅b+rи0≤r<b.a = q\cdot b + r \quad\text{и}\quad 0 \le r < b.a=q⋅b+rи0≤r<b. Программа (псевдокод): q := 000 r := aaa while r ≥\ge≥bbb do r := r −-− b q := q +++111 end Предусловие (безопасность входа): P: a≥0∧b>0P:\; a \ge 0 \land b > 0P:a≥0∧b>0. Постусловие (цель): Q: a=q⋅b+r∧0≤r<bQ:\; a = q\cdot b + r \land 0 \le r < bQ:a=q⋅b+r∧0≤r<b. Инвариант цикла. Натуральный инвариант — сохранение разложения исходного aaa через текущие q,rq,rq,r: I(q,r): a=q⋅b+r∧r≥0.I(q,r):\; a = q\cdot b + r \land r \ge 0.I(q,r):a=q⋅b+r∧r≥0. Построение инварианта (кратко). Идея: каждая итерация уменьшает rrr на ровно bbb и увеличивает qqq на 111, поэтому сумма q⋅b+rq\cdot b + rq⋅b+r должна оставаться равной исходному aaa. Дополнительно требуется гарантия, что rrr не уходит в отрицательное — это обеспечит корректность остатка и безопасность вычитания. Доказательство корректности по инварианту (три шага). 1) Инициализация: до цикла q=0q = 0q=0, r=ar = ar=a. Тогда a=0⋅b+a,
a = 0\cdot b + a, a=0⋅b+a,
поэтому I(q,r)I(q,r)I(q,r) выполняется при выполнении PPP (также r=a≥0r=a\ge0r=a≥0 из PPP). 2) Сохранение (индуктивный шаг): предположим I(q,r)I(q,r)I(q,r) верно перед телом цикла и выполнен условный переход r≥br \ge br≥b. После телa: r′=r−br' = r - br′=r−b, q′=q+1q' = q + 1q′=q+1. Тогда q′⋅b+r′=(q+1)⋅b+(r−b)=q⋅b+r=a,
q'\cdot b + r' = (q+1)\cdot b + (r-b) = q\cdot b + r = a, q′⋅b+r′=(q+1)⋅b+(r−b)=q⋅b+r=a,
и r′=r−b≥0r' = r-b \ge 0r′=r−b≥0 (так как r≥br\ge br≥b и b>0b>0b>0). Значит I(q′,r′)I(q',r')I(q′,r′) верно — инвариант сохраняется. 3) Выход и постусловие: цикл останавливается при ¬(r≥b)\lnot (r \ge b)¬(r≥b), т.е. при r<br < br<b. Выйдя из цикла, инвариант всё ещё верен, следовательно a=q⋅b+r∧r≥0.
a = q\cdot b + r \land r \ge 0. a=q⋅b+r∧r≥0.
Вместе с условием выхода даёт a=q⋅b+r∧0≤r<b,
a = q\cdot b + r \land 0 \le r < b, a=q⋅b+r∧0≤r<b,
что равно QQQ. Доказательство завершимости (терминирование). Введём функция меры (вариант) V(r)=rV(r) = rV(r)=r. При каждой итерации VVV уменьшается на bbb (по меньшей мере на 111, так как b>0b>0b>0), и при этом всегда остаётся неотрицательной по инварианту. Следовательно число итераций конечно — цикл завершается. Заключение. При предпосылке P: a≥0∧b>0P:\; a\ge0 \land b>0P:a≥0∧b>0 инвариант III корректно инициализируется и сохраняется, при выходе обеспечивает требуемое постусловие QQQ. Таким образом программа корректна и безопасна.
a=q⋅b+rи0≤r<b.a = q\cdot b + r \quad\text{и}\quad 0 \le r < b.a=q⋅b+rи0≤r<b.
Программа (псевдокод):
q := 000
r := aaa
while r ≥\ge≥ bbb do
r := r −-− b
q := q +++ 111
end
Предусловие (безопасность входа): P: a≥0∧b>0P:\; a \ge 0 \land b > 0P:a≥0∧b>0.
Постусловие (цель): Q: a=q⋅b+r∧0≤r<bQ:\; a = q\cdot b + r \land 0 \le r < bQ:a=q⋅b+r∧0≤r<b.
Инвариант цикла. Натуральный инвариант — сохранение разложения исходного aaa через текущие q,rq,rq,r:
I(q,r): a=q⋅b+r∧r≥0.I(q,r):\; a = q\cdot b + r \land r \ge 0.I(q,r):a=q⋅b+r∧r≥0.
Построение инварианта (кратко). Идея: каждая итерация уменьшает rrr на ровно bbb и увеличивает qqq на 111, поэтому сумма q⋅b+rq\cdot b + rq⋅b+r должна оставаться равной исходному aaa. Дополнительно требуется гарантия, что rrr не уходит в отрицательное — это обеспечит корректность остатка и безопасность вычитания.
Доказательство корректности по инварианту (три шага).
1) Инициализация: до цикла q=0q = 0q=0, r=ar = ar=a. Тогда
a=0⋅b+a, a = 0\cdot b + a,
a=0⋅b+a, поэтому I(q,r)I(q,r)I(q,r) выполняется при выполнении PPP (также r=a≥0r=a\ge0r=a≥0 из PPP).
2) Сохранение (индуктивный шаг): предположим I(q,r)I(q,r)I(q,r) верно перед телом цикла и выполнен условный переход r≥br \ge br≥b. После телa: r′=r−br' = r - br′=r−b, q′=q+1q' = q + 1q′=q+1. Тогда
q′⋅b+r′=(q+1)⋅b+(r−b)=q⋅b+r=a, q'\cdot b + r' = (q+1)\cdot b + (r-b) = q\cdot b + r = a,
q′⋅b+r′=(q+1)⋅b+(r−b)=q⋅b+r=a, и r′=r−b≥0r' = r-b \ge 0r′=r−b≥0 (так как r≥br\ge br≥b и b>0b>0b>0). Значит I(q′,r′)I(q',r')I(q′,r′) верно — инвариант сохраняется.
3) Выход и постусловие: цикл останавливается при ¬(r≥b)\lnot (r \ge b)¬(r≥b), т.е. при r<br < br<b. Выйдя из цикла, инвариант всё ещё верен, следовательно
a=q⋅b+r∧r≥0. a = q\cdot b + r \land r \ge 0.
a=q⋅b+r∧r≥0. Вместе с условием выхода даёт
a=q⋅b+r∧0≤r<b, a = q\cdot b + r \land 0 \le r < b,
a=q⋅b+r∧0≤r<b, что равно QQQ.
Доказательство завершимости (терминирование). Введём функция меры (вариант) V(r)=rV(r) = rV(r)=r. При каждой итерации VVV уменьшается на bbb (по меньшей мере на 111, так как b>0b>0b>0), и при этом всегда остаётся неотрицательной по инварианту. Следовательно число итераций конечно — цикл завершается.
Заключение. При предпосылке P: a≥0∧b>0P:\; a\ge0 \land b>0P:a≥0∧b>0 инвариант III корректно инициализируется и сохраняется, при выходе обеспечивает требуемое постусловие QQQ. Таким образом программа корректна и безопасна.