如何用C读取.cnf文件(合取范式)?

时间:2019-02-11 13:00:38

标签: c data-structures sat

文件如下所示。我需要阅读它们并将其存储在数据结构(可能是邻接表)中。但是我不知道如何忽略无用的注释并在“ p cnf”之后开始阅读。

c This Formula is generated by mcnf
c
c horn? no
c forced? no
c mixed sat? no
c clause length = 3
c
p cnf 20 91
4 -18 19 0
3 18 -5 0
-5 -8 -15 0
-20 7 -16 0
10 -13 -7 0
...

那是我的代码,只有在文件中没有字母时,它才可能起作用。

    // It would be the following code if the file starts with integers, but how could I change it if you were considering comments? I haven't debugged it yet so it might go wrong, I'll do it later.)

typedef struct LiteralNode {
    int linum; 
    int tag;    //When the variable is true, it is 1, else it is -1.
    struct LiteralNode *next;
} LiteralNode;

typedef struct ClauseNode {
    struct ClauseNode *next;
    int No;
    struct LiteralNode *info;
} ClauseNode;

typedef struct Clause {
    int literal_num;
    int clause_num;
    ClauseNode *root;
} Clause;
   Status CreateClause(Clause *cl, char *filename)
{
    int m, i = 0;
    ClauseNode *p, *q;
    q = (ClauseNode*)malloc(sizeof(ClauseNode));
    p = (ClauseNode*)malloc(sizeof(ClauseNode));
    LiteralNode *l1,*l2;
    p = cl -> root;
    l1 = (LiteralNode*)malloc(sizeof(LiteralNode));
    l2 = (LiteralNode*)malloc(sizeof(LiteralNode));
    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        return ERROR;
    }
    fscanf(fp,"%d", &cl -> clause_num);
    fscanf(fp, "%d",&cl -> literal_num);
    while(fscanf(fp, "%d", &m) != EOF){
        i++;
        q -> No = i;
        q -> next = NULL;
        l1 -> linum = m;
        l1 -> next = NULL;
        q -> info = l1;
        p -> next = q;
        p = q;
        fscanf(fp, "%d", &m);
        while (m != 0) {
            l2 -> linum = m;
            l2 -> tag = 0;
            l2 -> next = NULL;
            l1 -> next = l2;
            l1 = l2;
            fscanf(fp, "%d", &m);
        }
    }
    return OK;
}

data structure该图像与我用来存储CNF的数据结构有关。

1 个答案:

答案 0 :(得分:0)

您可以迭代行:如果一行以c开头或为空,则将其丢弃。如果以p开头:解析问题定义。如果以数字开头:切换到子句模式,并在不考虑行尾的情况下分析子句。 C标准库很好地帮助了它。

现在是C,而C并没有为任何复杂的数据结构提供良好的支持。实施数据结构需要格外小心!我们将从实现一个“简单的”动态大小的Clause类型开始:在C ++中,某些问题可以用std::vector<ClauseLiteral>解决。我们需要非常注意错误处理-否则程序的行为将是不确定的,我们根本不希望这样。我们会提前发现任何算术溢出!

#include <assert.h>
#include <stdint.h>
#include <stdlib.h>

typedef int ClauseLiteral;
static const int ClauseLiteralMax = INT_MAX;

typedef struct Clause {
  size_t size;
  size_t capacity; // does not include the terminating zero
  ClauseLiteral literals[1];
};

// Maximum capacity that doesn't overflow SIZE_MAX
static inline size_t Clause_max_capacity(void) {
  return (SIZE_MAX-sizeof(Clause))/sizeof(ClauseLiteral);
}

static size_t Clause_size_for_(size_t const count_of_literals) {
  assert(count_of_literals);
  if (count_of_literals > Clause_max_capacity()) return 0;
  return sizeof(Clause) + count_of_literals*sizeof(ClauseLiteral);
}

static size_t Clause_next_capacity_(size_t const capacity) {
  assert(capacity);
  const size_t growth_factor = 2;
  if (capacity > Clause_max_capacity()/growth_factor) {
    if (capacity < Clause_max_capacity()) return Clause_max_capacity();
    return 0;
  }
  return capacity * growth_factor;
}

static Clause *new_Clause_impl_(size_t const capacity) {
  size_t const alloc_size = Clause_size_for_(capacity);
  assert(alloc_size);
  Clause *const clause = calloc(alloc_size); // is zero-terminated
  if (!clause) return NULL;
  clause->size = 0;
  clause->capacity = capacity;
  return clause;
}

Clause *new_Clause(void) { return new_Clause_impl_(4); }

void free_Clause(Clause *clause) { free(clause); }

/** Assures that the clause exists and has room for at least by items */
bool Clause_grow(Clause **const clause_ptr, size_t by) {
  assert(clause_ptr);
  if (!*clause_ptr) return (*clause_ptr = new_Clause_impl_(by));
  Clause *const clause = *clause_ptr;
  assert(clause->size <= clause->capacity);
  if (clause->size > (SIZE_MAX - by)) return false; // overflow
  if (by > Clause_max_capacity()) return false; // won't fit
  if (clause->size > (Clause_max_capacity() - by)) return false; // won't fit
  size_t const new_size = clause->size + by;
  assert(new_size <= Clause_max_capacity());
  if (new_size > clause->capacity) {
    size_t new_capacity = clause->capacity;
    while (new_capacity && new_capacity < new_size)
      new_capacity = Clause_next_capacity_(new_capacity);
    if (!new_capacity) return false;
    Clause *const new_clause = realloc(clause, Clause_size_for_(new_capacity));
    if (!new_clause) return false;
    *clause_ptr = new_clause;
  }
  *clause_ptr->literals[new_size] = 0; // zero-terminate
  return true;
}

bool Clause_push_back(Clause **clause_ptr, ClauseLiteral literal) {
  assert(clause_ptr);
  assert(literal); // zero literals are not allowed within a clause
  if (!Clause_grow(clause_ptr, 1)) return false;
  (*clause_ptr)->literals[(*clause_ptr)->size++] = literal;
  return true;
}

我们现在可以通过阅读这些条款来增加这些条款。那么,让我们阅读吧!

#include <stdio.h>

typedef struct CNF {
  size_t variable_count;
  size_t clause_count;
  Clause *clauses[1];
};

static inline size_t CNF_max_clause_count() {
  return (SIZE_MAX-sizeof(CNF))/sizeof(Clause*);
}

static size_t CNF_size_for_(size_t const clause_count) {
  if (clause_count >= CNF_max_clause_count()) return 0;
  return sizeof(CNF) + clause_count * sizeof(Clause*);
}

static CNF *new_CNF(size_t variable_count, size_t clause_count) {
  assert(variable_count <= ClauseLiteralMax);
  size_t const cnf_size = CNF_size_fir(clause_count);
  CNF *cnf = calloc(cnf_size);
  if (!cnf) return NULL;
  cnf->variable_count = variable_count;
  cnf->clause_count = clause_count;
  return cnf;
}

static void free_CNF(CNF *const cnf) {
  if (!cnf) return;
  for (Clause **clause_ptr = &cnf->clauses[0]; *clause_ptr && clause+ptr < &cnf->clauses[clause_count]; clause_ptr++)
    free_Clause(*clause_ptr);
  free(cnf);
}

static CNF *read_p_line(FILE *file) {
  assert(file);
  size_t variable_count, clause_count;
  int match_count = fscanf(file, "p cnf %zd %zd", &variable_count, &clause_count);
  if (match_count != 2) return NULL;
  if (variable_count > ClauseLiteralMax) return NULL;
  return new_CNF(variable_count, clause_count);
}

static bool read_c_line(FILE *file) {
  assert(file);
  char c = fgetc(file);
  if (c != 'c') return false;
  while ((c = fgetc(file)) != EOF)
    if (c == '\n') return true;
  return false;
}  

static bool read_clauses(FILE *file, CNF *cnf) {
  assert(file);
  if (!cnf) return false;
  size_t const variable_count = cnf->variable_count;
  for (Clause **clause_ptr = &cnf->clauses[0]; clause_ptr < &cnf->clauses[clause_count];) {
    int literal;
    int match_count = fscanf(file, "%d", &literal);
    if (match_count != 1) return false;
    if (literal == 0) {
      if (!*clause_ptr) return false; // We disallow empty clauses.
      clause_ptr++;
    } 
    else if (literal >= -variable_count && literal <= variable_count) {
      if (!Clause_push_back(clause_ptr, literal)) return false;
    }
    else return false;
  }
  return true;
}

CNF *read_CNF(FILE *file) {
  assert(file);
  CNF *cnf = NULL;
  for (;;) {
    char const c = fgetc(file);
    if (c == EOF) goto error;
    if (isspace(c)) continue; // skip leading whitespace
    if (ungetc(c, file) == EOF) goto error;
    if (c == 'p' && !(cnf = read_p_line(file))) goto error;
    else if (c == 'c' && !read_c_line(file)) goto error;
    else if (isdigit(c)) break;
    goto error;
  }
  if (!read_clauses(file, cnf)) goto error;
  return cnf;
error:
  free_CNF(cnf);
  return NULL;
}

如您所见,该代码绝非易事,因为它是需要具有弹性且根本没有任何未定义行为的库代码。在C中,“简单”的事情可能会非常复杂。这就是为什么希望您宁愿在C ++中完成这项工作。