Лучший способ выразить "ровно один раз" в CBMC

Я очень стараюсь придумать лучшее решение для определения свойства "ровно один раз" в CBMC (средство проверки ограниченной модели C). Я имею в виду, что ровно одна позиция элемента в строке должна иметь значение 1 (или любое положительное число, которое может быть проверено как логическое значение true), остальные должны быть все нули.

Для М = 4

for(i=0;i<M;i++){
__CPROVER_assume( (update[i][0]) ?  
    ( !(update[i][1]) && !(update[i][2])  &&!(update[i][3]) ) :         
     ((update[i][1]) ?  (!(update[i][2])  && !(update[i][3]) ) :                  
     ((update[i][2]) ? !update[i][3] : update[i][3] )) )   ;
}`

Для М больше, чем это Это огромная проблема. Допустим, M = 8, я должен сделать что-то вроде:

for(i=0;i<M;i++){
   __CPROVER_assume( (update[i][0]) ?  ( !(update[i][1]) && !(update[i][2])  && !(update[i][3]) && (update[i][4]) && !(update[i][5])  && !(update[i][6]) && !(update[i][7]) )  :
           ((update[i][1]) ?  (!(update[i][2])  && !(update[i][3]) && !(update[i][4]) && !(update[i][5])  && !(update[i][6]) && !(update[i][7]) ) :
             ((update[i][2]) ? ((!update[i][3]) && !(update[i][4]) && !(update[i][5])  && !(update[i][6]) && !(update[i][7]))  :
                   ((update[i][3]) ? (!(update[i][4]) && !(update[i][5])  && !(update[i][6]) && !(update[i][7]))  : 
                   ((update[i][4]) ? (!(update[i][5])  && !(update[i][6]) && !(update[i][7])) : 
                      ((update[i][5]) ? (!(update[i][6]) && !(update[i][7])) :  
                         ((update[i][6]) ? !(update[i][7]) : (update[i][7])))))))) ;
}

Проверить нарушение ровно один раз легко, но заявить, что оно выглядит нетривиальным. У меня может быть еще один вариант: сформулировать задачу 2-мерного массива в задаче 1-мерного битового вектора, а затем выполнить умный xor. Но в настоящее время я не уверен в этом.

У кого-нибудь есть лучшее решение проблемы?

1 ответ

Решение

Как насчет подсчета количества истинных значений, а затем проверки их количества:

for (i = 0; i < M; i++) {
    int n_true = 0;
    int j;

    for (j = 0; j < M; j++) {
        n_true += (update[i][j] ? 1 : 0);
    }

    __CPROVER_assume(n_true == 1);
}
Другие вопросы по тегам