SAT問題を解くプログラム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
大工

SAT問題を解くプログラム

#1

投稿記事 by 大工 » 16年前

いつもお世話になっています,大工です.

いま,SAT問題(充足可能性問題)についてC++で作っています.
data.in に含まれるデータを隣接行列に見立ててそこから各ノードが隣接しているか判断しています.
data.in においては行列の上半分だけデータとして取り込んでいます.(下半分は同じ事なんで)
問題になっているのは sat.cpp での二重 for ループにある
// 論理関数に登録する.
booleanfunc.push_back(clause(tlit1, tlit2));
booleanfunc.push_back(clause(flit1, flit2));
が問題になっています.これを実行すると
a, b
0xbfae3e94
a1, b1,
0xbfae3e94
a0, b0,
a, c
0xbfae3e94
a1, c1,
0xbfae3e94
a0, c0,
0xbfae3e94
a1, c1,
0xbfae3e94
a0, c0,
a, e
0xbfae3e94
a1, e1,
0xbfae3e94
a0, e0,
0xbfae3e94
a1, e1,
0xbfae3e94
a0, e0,
0xbfae3e94
a1, e1,
0xbfae3e94
a0, e0,
と表示され期待通りになりません.
私が期待しているのは booleanfunc は
booleanfunc
+--------+--------+--------+--------+--------+
| 0x11 | 0x12 | 0x13 | 0x14 | 0x15 |
+--------+--------+--------+--------+--------+
このようにばらばらのアドレスを保存させたいのです.
(アドレスが一緒だったら引数を変えても同じものとりますもんね^^;)
関数 clause 内では新しく new で領域をとっているつもりなのですが同じ領域をとってしまいます.
どうにかならないでしょうか?
あと,ヘッダファイルで int a; とグローバル変数を定義すると
/tmp/cccIwGSL.o:(.bss+0x0): multiple definition of `a'
/tmp/cciZxMSI.o:(.bss+0x0): first defined here
collect2: ld はステータス 1 で終了しました
と怒られます.どのように回避出来ますか?

環境:Linux(Ubuntu8.10) 端末

===data.in===
1101
001
10
0
(上にグラフを描いてみました)
==sat.cpp== メインルーチンを含むプログラム
#include"sat.h"
#include<fstream>

int main(void) {

	int  NOTREV = 1;

	std::ifstream fin;
	std::list<std::list<Literal*>*> booleanfunc;
	std::list<std::list<Literal*>*>::iterator ipp;

	int nodes;
	std::cout << "How many nodes in the Graph? >>";
	std::cin >> nodes;

	fin.open(fname);
	if (!fin.is_open()) {

		// エラー処理.
		exit(1);
	}

	char c;
	char charac1, charac2;
	charac1 = 'a'; charac2 = 'b';

	for(int i = 0; i < nodes - 1; i++) {

		for(int j = 0; j < nodes - NOTREV; j++) {

			fin.get(c);
			if(CONECT == c) {

					// リテラルの生成.
					std::cout << charac1 << ", " << charac2 << std::endl;
					Literal tlit1(charac1, true), tlit2(charac2, true); 
					Literal flit1(charac1, false), flit2(charac2, false); 

					// 論理関数に登録する.
					booleanfunc.push_back(clause(tlit1, tlit2));
					booleanfunc.push_back(clause(flit1, flit2));

					for(ipp = booleanfunc.begin(); ipp != booleanfunc.end(); ipp++) {

						std::cout << *ipp << std::endl;
					}
			}

			charac2++;
		}
		// 改行を読み飛ばす.
		fin.get(c);
		charac1++;

		charac2 = 'b' + NOTREV;
		NOTREV++;
		break;
	}

	for(ipp = booleanfunc.begin(); ipp != booleanfunc.end(); ipp++) {

		//std::cout << *ipp << std::endl;
	}

	fin.close();

	return 0;
}
==sat.h== クラスの定義をするヘッダ
#include<iostream>
#include<stdlib.h>
#include<list>
#include<string>

const char CONECT = '1';
const char fname[/url] = "data.in";

class Expression {

	// コピーコンストラクタ・代入演算子の使用を禁止.
	private:
		Expression(const Expression&);
		Expression& operator=(const Expression&);

	protected:
		char char_;

	public:
		Expression() : char_(' '){}
		Expression(char c) : char_(c) {}
		char charac() {return char_;}
};

class Literal : public Expression {

	// var_:あり(false),なし(true).
	private:
		bool var_;

	public:
		Literal() : Expression(), var_(true)  {};
		Literal(char lt, bool var) : Expression(lt), var_(var) {};
		bool var() {return var_;}
};

std::list<Literal*>* clause(Literal&, Literal&);	  // clause 関数:節を作成する.
std::ostream& operator<<(std::ostream&, std::list<Literal*>*);
==func.cpp== 具体的な関数の定義をするプログラム
#include"sat.h"
#include<iostream>

std::list<Literal*>* clause(Literal& lit1, Literal& lit2) {

	std::list<Literal*>* clause;
	clause = new std::list<Literal*>;

	clause->push_back(&lit1);
	clause->push_back(&lit2);

	return clause;
}
std::ostream& operator<<(std::ostream& stream, std::list<Literal*>* lit) {

	std::list<Literal*>::iterator it;

	std::cout << &lit << std::endl;
	for(it = lit->begin(); it != lit->end(); it++) {

		stream << (*it)->charac() << (*it)->var();
		stream << ", ";
	}

	return stream;
}

Justy

Re:SAT問題を解くプログラム

#2

投稿記事 by Justy » 16年前


>表示され期待通りになりません.
>数 clause 内では新しく new で領域をとっているつもりなのですが同じ領域をとってしまいます

 たしかにclause()内部で newでリストを生成していますが、問題なのは
[color=sans-serif]
clause->push_back(&lit1);
clause->push_back(&lit2);
[/color]

 のようにポインタを入れていることです。
 これがヒープに確保されたポインタとかならばいいのですが、この lit1や lit2は
呼び出し元を見るとただのローカル変数です。

 ということはこの lit1や lit2は呼び出し元の if(CONECT == c)の {}が
終わった段階で消滅しているはずです。

 従って、最終的に出来上がったリストは破棄されたはずのクラスのポインタを指すリストになる、
というわけです。



>あと,ヘッダファイルで int a; とグローバル変数を定義すると
>/tmp/cccIwGSL.o:(.bss+0x0): multiple definition of `a'

 エラーメッセージに書いてあるとおりです。
 aが多重定義されているからです。
 同一名前空間の中で同じ名前を持つグローバル変数を複数のファイルで定義することは
できませんよ。

大工

Re:SAT問題を解くプログラム

#3

投稿記事 by 大工 » 16年前

clause関数は設計しなおします.ありがとうございました.

名前空間?ですか?namespaceはどこにも書いてないのですがこれはどういうことでしょうか?

Justy

Re:SAT問題を解くプログラム

#4

投稿記事 by Justy » 16年前


>名前空間?ですか?namespaceはどこにも書いてないのですが

 書いてなくても名前空間内に配置されます。
 この場合はグローバル名前空間ですね。

C++編(言語解説) 第18章 名前空間
ttp://www.geocities.jp/ky_webid/cpp/language/018.html
の下の方参照

大工

Re:SAT問題を解くプログラム

#5

投稿記事 by 大工 » 16年前

あ,なるほど・・・・
グローバル変数を使いたいときはどのようにすればよいのでしょうか?

Justy

Re:SAT問題を解くプログラム

#6

投稿記事 by Justy » 16年前

 このページが参考になるかと思います。


Cプログラミング診断室/これでもプロ/構造的欠陥
ttp://www.pro.or.jp/~fuji/mybooks/cdiag/cdiag.2.4.html

大工

Re:SAT問題を解くプログラム

#7

投稿記事 by 大工 » 16年前

sat.h の先頭と最後に
#ifndef INCLUDE_SAT_H_
#define INCLUDE_SAT_H_
===本体===
#endif
としましたが,変化はありませんでした...
あと,const をつけるとエラーが出ないのはなぜなのでしょうか?

Justy

Re:SAT問題を解くプログラム

#8

投稿記事 by Justy » 16年前


>としましたが,変化はありませんでした...

 すみません。
 こちらの方がわかりやすいかもしれません。

C言語編 第32章 ファイル分割
ttp://www.geocities.jp/ky_webid/c/032.html

 同じ名前のグローバル変数を複数のファイルで定義することは
できないので、1つのファイルにだけ定義し、後のファイルでは extern宣言を使って
参照するような形に書き直せばうまくいくはずです。



>あと,const をつけるとエラーが出ないのはなぜなのでしょうか?

 constをつけた場合変数ではなく定数として扱われ、デフォルトで内部リンケージ、
つまり static を付けたのと同じような扱いになりますので、多重定義のエラーにはなりません。
 
ロベールのC++教室 - 第69章 リンケージ -
ttp://www7b.biglobe.ne.jp/~robe/cpphtml/html01/cpp01069.html

大工

Re:SAT問題を解くプログラム

#9

投稿記事 by 大工 » 16年前

返信がおそくなりました.

なるほど,extren ですか・・・忘れてました><

閉鎖

“C言語何でも質問掲示板” へ戻る