Compiler errors 在操作此字段的(数组)字段时,循环不变量不够强

Compiler errors 在操作此字段的(数组)字段时,循环不变量不够强,compiler-errors,formal-verification,loop-invariant,dafny,Compiler Errors,Formal Verification,Loop Invariant,Dafny,已更新 关于解决一些dafny问题的问题,下面用给定的类和相应的方法描述。如果你还需要什么,请告诉我,提前谢谢你。此外,该链接在rise4fun中使用所有这些代码进行更新 class TextEdit { var text:array<char>; //conteúdo var scrap: array<char>; //conteúdo temporariamente guardado para copy/paste var tlen:int; //length di

已更新

关于解决一些dafny问题的问题,下面用给定的类和相应的方法描述。如果你还需要什么,请告诉我,提前谢谢你。此外,该链接在rise4fun中使用所有这些代码进行更新

class TextEdit {
var text:array<char>; //conteúdo
var scrap: array<char>; //conteúdo temporariamente guardado para copy/paste
var tlen:int; //length di text
var slen:int; //length di scrap
var at:int; //current position
var sellen:int; //length of the selection


method key(ch:char)
modifies this, text;
requires TextInv();
requires tlen+1<text.Length && sellen == 0;
ensures TextInv();
{
  var tempChar:array<char> := new array<char>;
  tempChar[0] := ch;

  insert(text, tlen, tempChar, 1, at );   
  at := at + 1;
  tlen := tlen + 1;
}


method select(sel:int, sl:int)
modifies this;
requires TextInv() && 0 <= sel && 0 <= sl && 0 <= sel+sl <= tlen;
ensures TextInv();
{
  at := sel; 
  sellen := sl;
}

method copy()
modifies this,scrap;
requires TextInv() && sellen > 0;
requires scrap != null;
ensures TextInv();
ensures slen == sellen;
{

  //emptying scrap
  delete(scrap, slen, 0, slen);
  slen := 0;

  var i:int := 0;
  while(i<sellen)
  invariant 0<=i<=sellen;
  invariant slen == i;
  //cada posição do scrap estará vazia 
  //invariant forall j :: 0<=j<i ==> scrap[j] == ' ';
  //só depois será preenchida
  invariant forall k :: i<=k<sellen ==> scrap[k] == text[at+k];
  {
    scrap[i] := text[at+i]; 
    slen := slen + 1; 
    i := i + 1;
  }

}

method cut()
requires scrap!=null && text!=null;
modifies this,text, scrap;
requires TextInv() && sellen > 0;
ensures TextInv();
ensures slen == sellen;
{
  //emptying scrap
  delete(scrap, slen, 0, slen);
  slen := 0;

  var i:int := 0;
  while(i<sellen)
  invariant i<=0<=sellen;
  //cada posição do scrap estará vazia 
 // invariant forall j :: 0<=j<i ==> scrap[j] == ' ';
  //só depois será preenchida
  invariant forall k :: i<=k<sellen ==> scrap[k] == text[at+k];
  {
    scrap[i] := text[at+i]; 
    slen := slen + 1;  
    i := i + 1;
  }
  delete(text, tlen, at, sellen);

  tlen := tlen - slen;
  }


method paste()
modifies this,text;
requires TextInv() && 0 <= slen+tlen < text.Length && sellen == 0;
ensures TextInv();
ensures tlen == old(tlen)+slen;
ensures at == old(at)+slen;
{
  if(slen>0)
  { 
    insert(text, tlen, scrap, slen, at );
    tlen := tlen + slen;
    at := at + slen;
  } 
}

function TextInv():bool 
reads this;
{
 text != null && 0 <= tlen <= text.Length && scrap != text &&
 0 <= at <= tlen && 0 <= sellen && 0 <= at+sellen <= tlen &&
 scrap != null && 0 <= slen <= scrap.Length == text.Length
}
method insert(line:array<char>, l:int, nl:array<char>, p:int, at:int)
  requires line != null && nl != null
  requires 0 <= l+p <= line.Length // line has enough space
  requires 0 <= p <= nl.Length // string in nl is shorter than nl
  requires 0 <= at <= l // insert position within line
  modifies line
  ensures line != null;
  ensures forall i :: (0<=i<p) ==> line[at+i] == nl[i] // ok now
{
  ghost var initialLine := line[..];

  // first we need to move the characters to the right
  var i:int := l;
  while(i>at)
    invariant line[0..i] == initialLine[0..i]
    invariant line[i+p..l+p] == initialLine[i..l]
    invariant at<=i<=l
  {
    i := i - 1;
    line[i+p] := line[i];
  }

  assert line[0..at] == initialLine[0..at];
  assert line[at+p..l+p] == initialLine[at..l];

  i := 0;
  while(i<p)
    invariant 0<=i<=p
    invariant line[0..at] == initialLine[0..at]
    invariant line[at..at+i] == nl[0..i]
    invariant line[at+p..l+p] == initialLine[at..l]
  {
    line[at + i] := nl[i];
    i := i + 1;
  }

  assert line[0..at] == initialLine[0..at];
  assert line[at..at+p] == nl[0..p];
  assert line[at+p..l+p] == initialLine[at..l];
}

method delete(line:array<char>, l:nat, at:nat, p:nat)
  requires line!=null
  requires l <= line.Length
  requires at+p <= l
  modifies line
  ensures line!=null
  ensures line[..at] == old(line[..at])
  ensures line[at..l-p] == old(line[at+p..l])
  ensures forall i :: l-p <= i < l ==> line[i] == ' '  
{
  var i:nat := 0;
  while(i < l-(at+p))
    invariant i <= l-(at+p)
    invariant at+p+i >= at+i 
    invariant line[..at] == old(line[..at])
    invariant line[at..at+i] == old(line[at+p..at+p+i])
    invariant line[at+i..l] == old(line[at+i..l]) // future is untouched
  { 
    line[at+i] := line[at+p+i];
    i := i+1;
  }

  var j:nat := l-p;
  while(j < l)
    invariant l-p <= j <= l
    invariant line[..at] == old(line[..at])
    invariant line[at..l-p] == old(line[at+p..l])
    invariant forall i :: l-p <= i < j ==> line[i] == ' '
  {
    line[j] := ' ';
    j := j+1;
  }
}
}
类文本编辑{
var text:array;//conteúdo
var scrap:array;//conteúdo temporariamente guardado para复制/粘贴
var-tlen:int;//长度di文本
var slen:int;//长度di废料
var at:int;//当前位置
var sellen:int;//选择的长度
方法键(ch:char)
修改此文本;
需要TextInv();

需要tlen+1我发现很难理解你的代码应该做什么-主要是因为变量名称很难理解。所以我只是通过盲目地加强不变量直到通过来验证它。在一个例子中,
cut
,我不得不为该方法添加一个附加的先决条件。我不知道这是否合适是否适合您的情况,但我认为它确实反映了该方法(目前的情况)的实际要求

分配阵列时,需要为其指定一个大小:

var tempChar:array<char> := new char[1];
您需要添加足够的事实,以确定数组访问是有界的,例如:

invariant sellen <= scrap.Length
invariant at+sellen <= text.Length
invariant 0 <= at
对象位于循环的modifies集合中。因此,您需要说明循环没有弄乱其字段:

modifies this,scrap
invariant TextInv()
您需要说明
scrap
数组中的对象仍然与方法的modifies集合中的对象相同:

invariant scrap == old(scrap)
其他说明:

  • 如果不需要变量为负值,请使用
    nat
    而不是
    int
  • 通常,你可以从后条件开始并向后操作来验证它。只要不断强化不变量和前提条件,直到它起作用。当然,你可能会发现前提条件现在太强了——如果是这样,你需要一个更有能力的实现
  • 类文本编辑{
    var text:array;//conteúdo
    var scrap:array;//conteúdo temporariamente guardado para复制/粘贴
    var-tlen:int;//长度di文本
    var slen:int;//长度di废料
    var at:int;//当前位置
    var sellen:int;//选择的长度
    方法键(ch:char)
    修改此文本;
    需要TextInv();
    
    需要tlen+1我认为代码中缺少一些部分。也许您可以将其放在rise4fun()上,并将其显示到相关错误的位置。然后使用指向该代码的链接更新问题。它看起来像“插入”和“删除”缺少方法?好的,我刚刚更新了question@lexicalscope这是指向代码最新版本的链接
    modifies this,scrap
    invariant TextInv()
    
    invariant scrap == old(scrap)
    
    class TextEdit {
    var text:array<char>; //conteúdo
    var scrap: array<char>; //conteúdo temporariamente guardado para copy/paste
    var tlen:int; //length di text
    var slen:int; //length di scrap
    var at:int; //current position
    var sellen:int; //length of the selection
    
    
    method key(ch:char)
    modifies this, text;
    requires TextInv();
    requires tlen+1<text.Length && sellen == 0;
    ensures TextInv();
    {
      var tempChar:array<char> := new char[1];
      tempChar[0] := ch;
    
      insert(text, tlen, tempChar, 1, at );   
      at := at + 1;
      tlen := tlen + 1;
    }
    
    
    method select(sel:int, sl:int)
    modifies this;
    requires TextInv() && 0 <= sel && 0 <= sl && 0 <= sel+sl <= tlen;
    ensures TextInv();
    {
      at := sel; 
      sellen := sl;
    }
    
    method copy()
    modifies this,scrap;
    requires TextInv() && sellen > 0;
    requires scrap != null;
    ensures TextInv();
    ensures slen == sellen;
    {
      //emptying scrap
      delete(scrap, slen, 0, slen);
      slen := 0;
    
      var i:nat := 0;
      while(i<sellen)
        modifies this,scrap
        invariant TextInv()
        invariant 0<=i<=sellen;
        invariant slen == i;
      //cada posição do scrap estará vazia 
      //invariant forall j :: 0<=j<i ==> scrap[j] == ' ';
      //só depois será preenchida
        invariant scrap != null && text != null;
        invariant sellen <= scrap.Length
        invariant at+sellen <= text.Length
        invariant 0 <= at
        invariant scrap[0..i] == text[at..at+i];
        invariant scrap == old(scrap)
      {
        scrap[i] := text[at+i]; 
        slen := slen + 1; 
        i := i + 1;
      }
    }
    
    method cut()
    //requires scrap!=null && text!=null;
    modifies this,text, scrap;
    requires TextInv() && sellen > 0;
    requires 0 <= at+sellen <= (tlen - (slen + sellen));
    ensures TextInv();
    ensures slen == sellen;
    {
      //emptying scrap
      delete(scrap, slen, 0, slen);
      slen := 0;
    
      assert 0 <= at+sellen <= (tlen - (slen + sellen));
    
      var i:int := 0;
      while(i<sellen)
      invariant 0<=i<=sellen;
      //cada posição do scrap estará vazia 
      //invariant forall j :: 0<=j<i ==> scrap[j] == ' ';
      //só depois será preenchida
      invariant scrap != null && text != null;
      invariant i <= scrap.Length
      invariant 0 <= at
      invariant at+i <= text.Length
      invariant scrap[0..i] == text[at..at+i];
      invariant slen + (sellen-i) <= scrap.Length;
      invariant slen + (sellen-i) == sellen;
      invariant TextInv()
      invariant scrap == old(scrap)
      invariant text == old(text)
      invariant 0 <= at+sellen <= (tlen - (slen + (sellen-i)));
      {
        scrap[i] := text[at+i]; 
        slen := slen + 1;  
        i := i + 1;
    
        /*assert text != null; 
        assert 0 <= tlen <= text.Length ; 
        assert scrap != text ; 
        assert 0 <= at <= tlen ; 
        assert 0 <= sellen ; 
        assert 0 <= at+sellen <= tlen ; 
        assert scrap != null ; 
        assert 0 <= slen <= scrap.Length == text.Length;*/
      }
    
      assert 0 <= at+sellen <= (tlen - slen);
    
      delete(text, tlen, at, sellen);
    
      assert 0 <= at+sellen <= (tlen - slen);
    
      tlen := tlen - slen;
    
      assert 0 <= at+sellen <= tlen ; 
    }
    
    
    method paste()
    modifies this,text;
    requires TextInv() && 0 <= slen+tlen < text.Length && sellen == 0;
    ensures TextInv();
    ensures tlen == old(tlen)+slen;
    ensures at == old(at)+slen;
    {
      if(slen>0)
      { 
        insert(text, tlen, scrap, slen, at );
        tlen := tlen + slen;
        at := at + slen;
      } 
    }
    
    function TextInv():bool 
    reads this;
    {
     text != null && 0 <= tlen <= text.Length && scrap != text &&
     0 <= at <= tlen && 0 <= sellen && 0 <= at+sellen <= tlen &&
     scrap != null && 0 <= slen <= scrap.Length == text.Length
    }
    method insert(line:array<char>, l:int, nl:array<char>, p:int, at:int)
      requires line != null && nl != null
      requires 0 <= l+p <= line.Length // line has enough space
      requires 0 <= p <= nl.Length // string in nl is shorter than nl
      requires 0 <= at <= l // insert position within line
      modifies line
      ensures line != null;
      ensures forall i :: (0<=i<p) ==> line[at+i] == nl[i] // ok now
    {
      ghost var initialLine := line[..];
    
      // first we need to move the characters to the right
      var i:int := l;
      while(i>at)
        invariant line[0..i] == initialLine[0..i]
        invariant line[i+p..l+p] == initialLine[i..l]
        invariant at<=i<=l
      {
        i := i - 1;
        line[i+p] := line[i];
      }
    
      assert line[0..at] == initialLine[0..at];
      assert line[at+p..l+p] == initialLine[at..l];
    
      i := 0;
      while(i<p)
        invariant 0<=i<=p
        invariant line[0..at] == initialLine[0..at]
        invariant line[at..at+i] == nl[0..i]
        invariant line[at+p..l+p] == initialLine[at..l]
      {
        line[at + i] := nl[i];
        i := i + 1;
      }
    
      assert line[0..at] == initialLine[0..at];
      assert line[at..at+p] == nl[0..p];
      assert line[at+p..l+p] == initialLine[at..l];
    }
    
    method delete(line:array<char>, l:nat, at:nat, p:nat)
      requires line!=null
      requires l <= line.Length
      requires at+p <= l
      modifies line
      ensures line!=null
      ensures line[..at] == old(line[..at])
      ensures line[at..l-p] == old(line[at+p..l])
      ensures forall i :: l-p <= i < l ==> line[i] == ' '  
    {
      var i:nat := 0;
      while(i < l-(at+p))
        invariant i <= l-(at+p)
        invariant at+p+i >= at+i 
        invariant line[..at] == old(line[..at])
        invariant line[at..at+i] == old(line[at+p..at+p+i])
        invariant line[at+i..l] == old(line[at+i..l]) // future is untouched
      { 
        line[at+i] := line[at+p+i];
        i := i+1;
      }
    
      var j:nat := l-p;
      while(j < l)
        invariant l-p <= j <= l
        invariant line[..at] == old(line[..at])
        invariant line[at..l-p] == old(line[at+p..l])
        invariant forall i :: l-p <= i < j ==> line[i] == ' '
      {
        line[j] := ' ';
        j := j+1;
      }
    }
    }