gpt4 book ai didi

c - 如何用C读取.cnf文件( union 范式)?

转载 作者:行者123 更新时间:2023-11-30 19:28:09 29 4
gpt4 key购买 nike

该文件如下所示。我需要读取它们并将它们存储在数据结构中(可能是邻接表)。但我不知道如何忽略无用的注释并在 '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 的数据结构。

最佳答案

您可以迭代这些行:如果一行以 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++ 中完成这项工作。

关于c - 如何用C读取.cnf文件( union 范式)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54631207/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com