-
-
Save gintenlabo/2793593 to your computer and use it in GitHub Desktop.
ほげほげ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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