Skip to content

Instantly share code, notes, and snippets.

@gintenlabo
Forked from siritori/NK.cpp
Created May 26, 2012 11:34
Show Gist options
  • Save gintenlabo/2793593 to your computer and use it in GitHub Desktop.
Save gintenlabo/2793593 to your computer and use it in GitHub Desktop.
ほげほげ
#include <iostream>
#include <map>
#include <cstdlib> // for std::exit
#include <boost/noncopyable.hpp>
using namespace std; // グローバル名前空間での using namespace std; は個人的には好きじゃない
// 毎回 std:: と書くか,関数内で using namespace std; した方が良いかも
enum PropType { // C++11 なら enum class を使う
IMPLIES,
AND,
OR,
NOT,
ATOMIC,
};
class Prop
: private boost::noncopyable // 継承前提のクラスは noncopyable にするのが吉
{
public:
virtual ~Prop() {}
virtual PropType type() const = 0;
friend ostream &operator<<(ostream &stream, const Prop *p) {
return p->print(stream);
}
friend ostream &operator<<(ostream &stream, const Prop &p) {
return p.print(stream);
}
private:
virtual ostream &print(ostream &stream) const = 0;
};
typedef map<char, const Prop*> assumption;
class AtomicProp : public Prop {
const char ch_; // private メンバは後に書く方が個人的には好み
public:
explicit AtomicProp(const char ch):ch_(ch){}
PropType type() const { // C++11 なら override を付けたほうが良いかも
return ATOMIC;
}
char name() const {
return ch_;
}
private:
ostream &print(ostream &stream) const { // 同じく override 推奨. 以下省略
stream << ch_;
return stream; // print は void を返して, operator<< 側で戻り値を指定したほうが良いかも
}
};
class NotProp : public Prop {
const Prop *prop_; // const Prop* const prop_; でも良いね!
public:
explicit NotProp(const Prop *p):prop_(p){}
PropType type() const {
return NOT;
}
private:
ostream &print(ostream &stream) const {
if(NOT > prop_->type()) stream << "¬(" << prop_ << ")";
else stream << "¬" << prop_;
return stream;
}
};
class AndProp : public Prop {
const Prop *lp_;
const Prop *rp_;
public:
explicit AndProp(const Prop *lp, const Prop *rp):lp_(lp),rp_(rp){}
PropType type() const {
return AND;
}
const Prop *lhs() const {
return lp_;
}
const Prop *rhs() const {
return rp_;
}
private:
ostream &print(ostream &stream) const {
if(AND >= lp_->type()) stream << "(" << lp_ << ")";
else stream << lp_;
stream << " ∧ ";
if(AND > rp_->type()) stream << "(" << rp_ << ")";
else stream << rp_;
return stream;
}
};
class OrProp : public Prop {
const Prop *lp_;
const Prop *rp_;
public:
explicit OrProp(const Prop *lp, const Prop *rp):lp_(lp),rp_(rp){}
PropType type() const {
return OR;
}
const Prop *lhs() const {
return lp_;
}
const Prop *rhs() const {
return rp_;
}
private:
ostream &print(ostream &stream) const {
if(OR >= lp_->type()) stream << "(" << lp_ << ")";
else stream << lp_;
stream << " ∨ ";
if(OR > rp_->type()) stream << "(" << rp_ << ")";
else stream << rp_;
return stream;
}
};
class ImpliesProp : public Prop {
const Prop *lp_;
const Prop *rp_;
public:
explicit ImpliesProp(const Prop *lp, const Prop *rp):lp_(lp),rp_(rp){}
PropType type() const {
return IMPLIES;
}
const Prop *lhs() const {
return lp_;
}
const Prop *rhs() const {
return rp_;
}
private:
ostream &print(ostream &stream) const {
if(AND >= lp_->type()) stream << "(" << lp_ << ")";
else stream << lp_;
stream << " -> ";
if(AND > rp_->type()) stream << "(" << rp_ << ")";
else stream << rp_;
return stream;
}
};
class Theorem {
assumption asp_;
const Prop *con_; // conclusion
public:
// law of excluded middle
explicit Theorem(const Prop *con):con_(con) {}
// assumption
explicit Theorem(const Prop *con, const char name):con_(con) {
assumption::iterator it = asp_.find(name);
if(it != asp_.end()) asp_.erase(it);
asp_.insert(pair<char, const Prop*>(name, con_));
}
// ordinaly constructor 1
explicit Theorem(const Prop *con, const assumption &asp)
:asp_(asp),con_(con){}
// ordinaly constructor 2
explicit Theorem(const Prop *con, const assumption &asp1, const assumption &asp2)
:asp_(asp1),con_(con) {
asp_.insert(asp2.begin(), asp2.end());
}
friend ostream &operator<<(ostream &stream, const Theorem *th) {
// th->asp_ って毎回書くのは面倒なので参照化
assumption const & asp = th->asp_;
for( assumption::const_iterator it = asp.begin(), end = th->asp_.end();
it != end; ++it )
{
stream << it->first << ":" << it->second << endl;
}
/*
// ちなみに C++11 なら range_based for で書ける
for( auto const& p : th->asp_ ) {
stream << p.first << ":" << p.second << endl;
}
*/
if(asp.empty()) {
stream << "no assumptions" << endl;
}
stream << "-------------------" << endl;
stream << th->con_ << endl;
return stream;
}
const assumption& asp() const {
return asp_;
}
const Prop *con() const {
return con_;
}
const Prop *name2prop(const char name) const {
assumption::const_iterator it = asp_.find(name);
if(it == asp_.end()) return NULL;
return it->second;
}
};
namespace Rule {
Theorem *and_intro(Theorem *t1, Theorem *t2) {
const AndProp *con = new AndProp(t1->con(), t2->con());
return new Theorem(con, t1->asp(), t2->asp());
}
Theorem *and_elim1(Theorem *t) {
if(t->con()->type() != AND) exit(1);
const AndProp *p = (AndProp*)t->con();
const Prop *con = p->lhs();
return new Theorem(con, t->asp());
}
Theorem *and_elim2(Theorem *t) {
if(t->con()->type() != AND) exit(1);
const AndProp *p = (AndProp*)t->con();
const Prop *con = p->rhs();
return new Theorem(con, t->asp());
}
Theorem *implication_intro(Theorem *t, const char name) {
const Prop *p = t->name2prop(name);
assumption asp = t->asp();
asp.erase(name);
return new Theorem(new ImpliesProp(p, t->con()), asp);
}
Theorem *or_intro1(Theorem *t, const Prop *p) {
return new Theorem(new OrProp(t->con(), p), t->asp());
}
Theorem *or_intro2(Theorem *t, const Prop *p) {
return new Theorem(new OrProp(p, t->con()), t->asp());
}
Theorem *lem(const Prop *p) {
return new Theorem(new OrProp(p, new NotProp(p)));
}
}
void test1() {
Theorem *a = new Theorem(new AndProp(new AtomicProp('A'), new AtomicProp('B')), 'a');
cout << a << endl;
Theorem *t1 = Rule::and_elim2(a);
cout << t1 << endl;
Theorem *t2 = Rule::and_elim1(a);
cout << t2 << endl;
Theorem *t3 = Rule::and_intro(t1, t2);
cout << t3 << endl;
Theorem *con = Rule::implication_intro(t3, 'a');
cout << con << endl;
}
void test2() {
Theorem *a = new Theorem(new AtomicProp('B'), 'b');
Theorem *b = Rule::or_intro2(a, new AtomicProp('A'));
Theorem *con = Rule::implication_intro(b, 'b');
cout << con;
}
int main(void) {
// A ∧ B -> B ∧ A
test1();
cout << endl << endl;
// B -> A ∨ B
test2();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment