首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Dafny GCD引理证明

Dafny GCD引理证明
EN

Stack Overflow用户
提问于 2021-09-21 12:54:06
回答 1查看 316关注 0票数 0

我想用dafny证明下面关于gcd的引理:对于所有k个自然数,如果k|a和k|b,则k|gcd(a,b)。到目前为止,我有以下代码:

代码语言:javascript
复制
// Euclid's algorithm for computing the greatest common divisor
function gcd(a: nat, b: nat): nat
    requires a > 0 && b > 0
{
    if a == b then a else 
    if b > a then gcd(a, b - a) else 
    gcd(a - b, b) 
}

predicate divides(a: nat, b:nat)
    requires a > 0
{
exists k: nat :: b == k * a
}

lemma dividesLemma(a: nat, b: nat)
//k|a && k|b ==> k|gcd(a,b)
requires a > 0 && b > 0
    ensures gcd(a,b) > 0
    ensures forall k: nat :: divides(a,k) && divides(b,k) ==> divides(gcd(a,b),k)
{
    if(a == b) {
        assert a * 1 == gcd(a,b);
        assert b * 1 == gcd(a,b);
    } else if b > a {
        if(divides(a, b)) {
            assert divides(a,a);
            assert divides(a,b);
            assert divides(a, gcd(a,b));
        } else {
            dividesLemma(a, b - a);
        }
    } else {
        if(divides(b, a)) {
            assert divides(b,b);
            assert divides(b,a);
            assert divides(b, gcd(a,b));
        } else {
            dividesLemma(a, a - b);
        }
    }
}

我知道如何用手来做证明。我会考虑a和b的素数分解,并说gcd(a,b)是组合的素数分解,使得我们从每个素数分解中取最少的素数。例如,如果a=9,b= 15,9的素数分解= 3x3,15的素数分解= 3x5,所以gcd(9,5) =3,因为这是它们素数分解的最小组合。利用这一事实,应该很清楚,如果k|b和k|a,k一定包含这些最小素数。我怎么用dafny来表达呢?目前,我正在考虑基本情况if a=b和if a|b或b|a,但不确定如何合并a和b在素数分解中可能不共享公素数这一事实。

对此任何帮助都将不胜感激!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-12 05:55:15

divides的调用方式有问题。我认为在确保条款中,你指的是divides(k, a)而不是divides(a, k),类似于divides(b, k)divides(gcd(a, b), k)

在递归调用dividesLemma(a, b - a)之后,一种方法是使用方法的后置条件。这里我们知道,对于所有的kk除以ak除以b - a,这意味着k除以gcd(a, b-a)。使用此信息,我们尝试证明所需的后置条件(代码或证明简单易懂)

代码语言:javascript
复制
dividesLemma(a, b - a);
assert gcd(a, b) == gcd(a, b-a);
assert forall k : nat :: k > 0 && divides(k, a) && divides(k, b-a) ==> divides(k, gcd(a, b));
forall k : nat | k > 0 && divides(k, a) && divides(k, b) ensures divides(k, gcd(a, b)) {
    var m :| a == m * k;
    var n :| b == n * k;
    assert (b - a) == (n - m) * k;
    assume n >= m;
    assert divides(k, a);
    assert divides(k, b-a);
    // Implied from last assert forall
    assert divides(k, gcd(a, b)); 
}

这里我假设是n >= m,因为divides要求n-mnat,这可以单独证明。

另外,第二个递归调用应该是dividesLemma(a - b, b)

代码语言:javascript
复制
function gcd(a: nat, b: nat): nat
  requires a > 0 && b > 0
{
  if a == b
    then a
  else if a < b
    then gcd(a, b-a)
  else gcd(a-b, b)
}

predicate divides(a: nat, b: nat)
  requires a > 0 && b > 0
{
  exists k: nat :: b == k * a
}

lemma helper(a: nat, b: nat, k : nat)
  requires a > 0 && b > 0 && k > 0
  requires divides(k, a) && divides(k, b)
  requires b >= a
  ensures exists m, n :: a == m * k && b == n * k && m <= n;
{ }
    
lemma dividesLemma(a: nat, b: nat)
  decreases a + b
  requires a > 0 && b > 0
  ensures gcd(a, b) > 0
  ensures forall k: nat :: k > 0 && divides(k, a) && divides(k, b) ==> divides(k, gcd(a, b))
{
  if (a == b){
  }
  else if (b > a){
    dividesLemma(a, b - a);
    assert gcd(a, b) == gcd(a, b-a);
    assert forall k : nat :: k > 0 && divides(k, a) && divides(k, b-a) ==> divides(k, gcd(a, b));
    forall k : nat | k > 0 && divides(k, a) && divides(k, b) ensures divides(k, gcd(a, b)) {
      helper(a, b, k);
      var m, n :| a == m * k && b == n * k && m <= n;
      assert b - a == (n - m) * k;
      assert divides(k, b-a);
    }
  }
  else {
    dividesLemma(a - b, b);
    assert gcd(a, b) == gcd(a - b, b);
    assert forall k : nat :: k > 0 && divides(k, a-b) && divides(k, b) ==> divides(k, gcd(a, b));
    forall k : nat | k > 0 && divides(k, a) && divides(k, b) ensures divides(k, gcd(a, b)) {
      helper(b, a, k);
      var m, n :| b == m * k && a == n * k && m <= n;
      assert a - b == (n - m) * k;
      assert divides(k, a-b);
    }
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69269257

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档