[置顶] 命题逻辑之自然推理

标签: c 假言推理  消解法  离散数学 
41人阅读 评论(2) 收藏 举报
分类:

离散数学中有这样一种证明题:!B,A→B,C→D,A∨B => D

如何用C++编码的方法导出推理过程呢?

①我们先看结果:



②程序的食用说明:

1.前提中只能出现析取(+),单条件(-),双条件(=)和文字(p或!p),且均为简单式

2.结论中只能够是文字(p或!p)

3.推理的某些步骤可能是不必要的,但还是输出了

③程序的原理:

有两个版本,一个基于“假言推理”,一个基于“消解法”

假言推理:A(A→B)=> B

消解法:A∧(!A→B) => B

1、定义一个结构体Sentence,成员包含:

primary:原字符串;

【若是条件式】前件left,后件right(left→right)(或者保存析取式的左右部分)

【若不是前提条件】basis[0]和basis[1]保存了推出此式的依据编号

【若不是前提条件】字符串reason保存了推出此式的理由

Pos:保存了该式子的编号

isLetter、isCond:是否为文字、是否为条件式(消解式)

2、处理输入(假言推理)

遇到析取式:转换为2个单条件式;

遇到双条件式:转换为4个单条件式;

遇到单条件式:再衍生出1个逆否单条件式;

遇到其它:无法处理,直接保存;

(注意要把!!p处理成!p,把!!!p处理为!p)

处理输入(消解法)

遇到析取式:直接保存;

遇到双条件式:转换为2个单条件式,再转化为两个析取式;

遇到单条件式:转化为1个析取式;


3、开始推理(敲黑板):

在所有结构体中搜索文字;

找到文字再搜索条件式,若条件式的前件与文字相同,则使用“假言推理”(或“消解法”,前件或后件有一个与文字相同)(这也是推理过程中唯一使用的定理,无法使用传递律等……),以条件式的后件创建一个结构体放入结构体组的尾部;

继续搜索……

(其实就是一个双层for循环)

4、输出我们的推理过程

如果结论与我们推理过程中某个文字相同,就代表我们推理成功,立即停止推理

若到最后都无法找到匹配的文字,则输出推理失败。

“假言推理”版本如下:

/*  std == c++11  */
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <algorithm>
using namespace std;

//改进1:将字符操作改为string操作,极大地增强了可读性
struct Sentence
{
	string primary;			//primary string
	string left, right;		//left - right (isCondition == true)
	int basis[2] = { 0 };	//store the number of reasons
	string reason;			//how conducts to it (isPrim == false)
	int Pos = 0;			//position
	bool isLetter, isCond, isUsed = 0;
};

//改进2:利用find()和replace()将!!p改成p,降低了编写难度
void to_pos( string &a )
{
	size_t p;
	while ((p = a.find( "!!" ) + 1)) a.erase( p - 1, 2 );
}

//改写:原函数int setNiyou();
//解释:			目标数组				 初始字符串   左件		右件    编号   推理理由	  依据1   依据2   是否条件式	 是否文字
void setStc( vector<Sentence>& stc, string pri, string l, string r, int p, string& re, int r1, int r2, bool isC, bool isL)
{
	Sentence tmp;
	tmp.primary = pri;
	tmp.left = l;
	tmp.right = r;
	tmp.reason = re;
	tmp.Pos = p;
	tmp.basis[0] = r1;
	tmp.basis[1] = r2;
	tmp.isCond = isC;
	tmp.isLetter = isL;

	stc.push_back( tmp );
}

//改写:原函数int inputPrimary();
//解释:将所有前提尽可能转化为条件式
int inputPrim( vector<Sentence>& stc )
{
	int count = 1;			//NO.count
	size_t con;	//the position of the connect-sign
	string re1 = "前提条件";
	string re2 = "原命题的逆否命题";
	string re3 = "双条件导出的条件式";
	string re4 = "析取式转换为条件式";

	string temp, left, right;
	while (getline( cin, temp ) && temp.empty() == false)
	{
		//p or !p
		if (temp.length() == 1 || (temp.length() == 2 && temp[0] == '!'))
		{
			setStc( stc, temp, "", "", count, re1, 0, 0, 0, 1 );
			++count;
		}
		else
		{
			con = temp.find_first_of( "-=+" );
			//others
			if (con == temp.length())
			{
				setStc( stc, temp, "", "", count, re1, 0, 0, 0, 0 );
				++count;
			}
			else
			{
				if (temp[con] == '-')
				{
					//p-q
					left = string( temp.begin(), temp.begin() + con );
					right = string( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re1, 0, 0, 1, 0 );
					++count;
					//!q-!p
					temp = "!" + right + "-!" + left;
					to_pos( temp );
					con = temp.find( "-" );
					left = string( temp.begin(), temp.begin() + con );
					right = string( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re2, count - 1, 0, 1, 0 );
					++count;
				}
				else if (temp[con] == '=')
				{
					//p=q
					setStc( stc, temp, "", "", count, re1, 0, 0, 0,  0);
					++count;
					//p-q
					temp[con] = '-';
					left = string( temp.begin(), temp.begin() + con );
					right = string( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re3, count - 1, 0, 1, 0 );
					++count;
					//q-p
					temp = right + '-' + left;
					setStc( stc, temp, right, left, count, re3, count - 2, 0, 1, 0 );
					++count;
					//修复1:!p-!q
					temp = "!" + left + "-!" + right;
					to_pos( temp );
					con = temp.find( "-" );
					left = string( temp.begin(), temp.begin() + con );
					right = string( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re2, count - 1, 0, 1, 0 );
					++count;
					//修复2:!q-!p
					temp = right + '-' + left;
					setStc( stc, temp, right, left, count, re2, count - 3, 0, 1, 0 );
					++count;
				}
				else if (temp[con] == '+')
				{
					//p+q
					setStc( stc, temp, "", "", count, re1, 0, 0, 0, 0 );
					++count;
					//!p-q
					temp[con] = '-';
					temp = '!' + temp;
					to_pos( temp );
					con = temp.find( "-" );
					left = string( temp.begin(), temp.begin() + con );
					right = string( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re4, count - 1, 0, 1, 0 );
					++count;
					//!q-p
					temp = "!" + right + "-!" + left;
					to_pos( temp );
					con = temp.find( "-" );
					left = string( temp.begin(), temp.begin() + con );
					right = string( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re4, count - 2, 0, 1, 0 );
					++count;
				}
			}
		}
	}
	//改进3:删除按字符串长度排序
	return count;
}

//改写:void printYsh()
//解释:若推理式与目标一致,推理成功
void printStc( vector<Sentence> stc, const string& result )
{
	for (size_t i = 0; i != stc.size(); ++i)
	{
		cout << "(" << stc[i].Pos << ")" << "\t\t" << left << setw( 10 ) << stc[i].primary + "为真" << "\t\t";
		if (stc[i].basis[0]) cout << "(" << stc[i].basis[0] << ")";
		if (stc[i].basis[1]) cout << "(" << stc[i].basis[1] << ")";
		cout << stc[i].reason << endl;

		if (stc[i].primary == result)
		{
			cout << endl << "推理成功!";
			return;
		}
	}
	cout << endl << "推理失败";
}

//改进4:新增函数infer(),简化main(),增强可读性
//解释:利用假言推理得到新的文字
void infer( vector<Sentence>& stc )
{
	int count = stc.size() + 1;
	string re5 = "假言推理";

	for (size_t i = 0; i != stc.size(); ++i)
	{
		if (!stc[i].isLetter) continue;
		for (size_t j = 0; j != stc.size(); ++j)
		{
			if (stc[j].isCond &&stc[j].isUsed == 0 && stc[j].left == stc[i].primary)
			{
				stc[j].isUsed = 1;
				setStc( stc, stc[j].right, "", "", count, re5, i + 1, j + 1, 0, 1 );
				++count;
			}
		}
	}
}

int main()
{
	//改进5:使用vector,方便使用且节约内存
	vector<Sentence> stc;
	cout << "请输入前提:" << endl;
	inputPrim( stc );
	infer( stc );

	string result;
	cout << "请输入结论:";
	getline( cin, result );

	cout << endl << "推理如下:" << endl;
	printStc( stc, result );

	system( "pause" );
	return 0;
}

“消解法”版本如下:

/*  std == c++11  */
#include <iostream>
#include <string>
#include <vector>
#include <iomanip>
#include <algorithm>
using namespace std;

//改进1:将字符操作改为string操作,极大地增强了可读性
struct Sentence
{
	string primary;			//primary string
	string left, right;		//left + right (isCond == true )
	size_t basis[2] = { 0 };	//store the number of reasons
	string reason;			//how conducts to it (isPrim == false)
	size_t Pos = 0;			//position
	bool isLetter, isCond, isUsed = 0;
};

//改进2:利用find()和replace()将!!p改成p,降低了编写难度
void to_pos( string &a )
{
	size_t p;
	while ((p = a.find( "!!" ) + 1)) a.erase( p - 1, 2 );
}

//改写:原函数int setNiyou();
//解释:			目标数组				 初始字符串		          A		            B		    编号      推理理由	        依据1      依据2   是否析取式  是否文字
void setStc( vector<Sentence>& stc, const string& pri, const string& l, const string& r, size_t p, const string& re, size_t r1, size_t r2, bool isC, bool isL )
{
	Sentence tmp;
	tmp.primary = pri;
	tmp.left = l;
	tmp.right = r;
	tmp.reason = re;
	tmp.Pos = p;
	tmp.basis[0] = r1;
	tmp.basis[1] = r2;
	tmp.isCond = isC;
	tmp.isLetter = isL;

	stc.push_back( tmp );
}

//改写:原函数int inputPrimary();
//解释:将所有前提尽可能转化为析取式
int inputPrim( vector<Sentence>& stc )
{
	int count = 1;						//NO.count
	size_t con;							//the position of the connect-sign
	string re1 = "前提条件";
	string re2 = "条件式导出的析取式";
	string re3 = "双条件导出的条件式";

	string temp, left, right;
	while (getline( cin, temp ) && temp.empty() == false)
	{
		//p or !p
		if (temp.length() == 1 || (temp.length() == 2 && temp[0] == '!'))
		{
			setStc( stc, temp, "", "", count, re1, 0, 0, 0, 1 );
			++count;
		}
		else
		{
			con = temp.find_first_of( "-=+" );
			//others
			if (con == string::npos)
			{
				setStc( stc, temp, "", "", count, re1, 0, 0, 0, 0 );
				++count;
			}
			else
			{
				if (temp[con] == '-')
				{
					//p-q
					setStc( stc, temp, "", "", count, re1, 0, 0, 0, 0 );
					++count;
					//!p+q
					temp[con] = '+';
					temp = "!" + temp;
					to_pos( temp );
					con = temp.find( "+" );
					left.assign( temp.begin(), temp.begin() + con );
					right.assign( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re2, count - 1, 0, 1, 0 );
					++count;
				}
				else if (temp[con] == '=')
				{
					//p=q
					setStc( stc, temp, "", "", count, re1, 0, 0, 0, 0 );
					++count;
					//p-q
					temp[con] = '-';
					setStc( stc, temp, "", "", count, re3, count - 1, 0, 0, 0 );
					++count;
					//q-p
					left.assign( temp.begin() + con + 1, temp.end() );
					right.assign( temp.begin(), temp.begin() + con );
					temp = left + "-" + right;
					setStc( stc, temp, right, left, count, re3, count - 2, 0, 0, 0 );
					++count;
					//!p+q
					temp = "!" + right + "+" + left;
					to_pos( temp );
					con = temp.find( "+" );
					left.assign( temp.begin(), temp.begin() + con );
					right.assign( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re2, count - 2, 0, 1, 0 );
					++count;
					//!q+p
					temp = "!" + right + "+!" + left;
					to_pos( temp );
					con = temp.find( "+" );
					left.assign( temp.begin(), temp.begin() + con );
					right.assign( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re2, count - 2, 0, 1, 0 );
					++count;
				}
				else if (temp[con] == '+')
				{
					//p+q
					left.assign( temp.begin(), temp.begin() + con );
					right.assign( temp.begin() + con + 1, temp.end() );
					setStc( stc, temp, left, right, count, re1, 0, 0, 1, 0 );
					++count;
				}
			}
		}
	}
	//改进3:删除按字符串长度排序
	return count;
}

//改写:void printYsh()
//解释:若推理式与目标一致,推理成功
void printStc( vector<Sentence> stc, const string& result )
{
	for (size_t i = 0; i != stc.size(); ++i)
	{
		cout << "(" << stc[i].Pos << ")" << "\t\t" << left << setw( 10 ) << stc[i].primary + "为真" << "\t\t";
		if (stc[i].basis[0]) cout << "(" << stc[i].basis[0] << ")";
		if (stc[i].basis[1]) cout << "(" << stc[i].basis[1] << ")";
		cout << stc[i].reason << endl;

		if (stc[i].primary == result)
		{
			cout << endl << "推理成功!";
			return;
		}
	}
	cout << endl << "推理失败";
}

//新增:判断匹配函数(!p和p匹配)
bool isMatch( const string& a, const string& b )
{
	if (a == "!" + b) return true;
	if (b == "!" + a) return true;
	return false;
}

//改进4:新增函数infer(),简化main(),增强可读性
//解释:利用消解式得到新的文字
void infer( vector<Sentence>& stc )
{
	size_t count = stc.size() + 1;
	string re4 = "消解法";

	for (size_t i = 0; i != stc.size(); ++i)
	{
		if (!stc[i].isLetter) continue;
		for (size_t j = 0; j != stc.size(); ++j)
		{
			if (stc[j].isCond &&stc[j].isUsed == 0)
			{
				if (isMatch( stc[j].left, stc[i].primary ))
					setStc( stc, stc[j].right, "", "", count, re4, i + 1, j + 1, 0, 1 );
				else if (isMatch( stc[j].right, stc[i].primary ))
					setStc( stc, stc[j].left, "", "", count, re4, i + 1, j + 1, 0, 1 );
				else continue;
				stc[j].isUsed = 1;
				++count;
			}
		}
	}
}

int main()
{
	//改进5:使用vector,方便使用且节约内存
	vector<Sentence> stc;
	cout << "请输入前提:" << endl;
	inputPrim( stc );
	infer( stc );

	string result;
	cout << "请输入结论:";
	getline( cin, result );

	cout << endl << "推理如下:" << endl;
	printStc( stc, result );

	system( "pause" );
	return 0;
}

如果有BUG,欢迎评论,谢谢观看~

查看评论

使用DLL文件中封装的窗口

使用DLL文件中封装的窗口徐长友文章摘要:     编写软件时常常使用到DLL文件,本文就使用DLL文件中封装的窗口来说说Delphi中在DLL如何封装窗口,如何调用DLL中封装的窗口,及MDI-Ch...
  • yousoft
  • yousoft
  • 2001-10-12 08:29:00
  • 1553

离散数学笔记三--命题逻辑的推理理论

第三章命题逻辑的推理理论 1.推理的形式结构 (1)定义3.1:设A1,A2,A3...Ak和B都是命题公式,若对于A1,A2,A3...Ak和B中出现的命题变项的任意一组赋值,或者A1,A2,A3....
  • u011531613
  • u011531613
  • 2017-03-05 18:44:21
  • 2429

程序设计题: 命题逻辑应用系统

命题逻辑应用系统 1 问题描述        该系统要求实现命题逻辑中基本算法及其应用系统,包括真值表的计算、主析取和主合取范式的计算。通过此课题,熟练掌握命题公式的计算机表示、命题等价常见算法的实...
  • Tc_To_Top
  • Tc_To_Top
  • 2015-10-31 12:15:50
  • 1244

数理逻辑:命题逻辑(8)完全范式

  • zzwu
  • zzwu
  • 2012-10-19 11:28:29
  • 820

命题逻辑和谓词逻辑的异同

关键词:命题逻辑、谓词逻辑、一阶谓词逻辑、 “所有个体”、“存在个体”中,量词加在论域的个体上,称为一阶量词。  在一阶逻辑中使用的量词仅限于一阶量词。 “所有函数”、“存在函数”、“所有关系”和“存...
  • bruceyang2009lzu
  • bruceyang2009lzu
  • 2011-12-20 20:21:35
  • 9603

刑侦推理暴力解法c++版

#include&amp;lt;iostream&amp;gt; #include&amp;lt;cmath&amp;gt; #include&amp;lt;vector&amp;gt; using ...
  • gitprx
  • gitprx
  • 2018-03-05 01:27:28
  • 33

《离散数学》学习笔记一之命题逻辑

命题逻辑     命题:
  • u013824975
  • u013824975
  • 2014-06-17 20:03:47
  • 1879

1049 命题逻辑(java)— 离散数学应用(详解)

问题描述  在命题逻辑中,每个变元可以取值为真或假,通过逻辑运算符连接得到逻辑表达式,逻辑表达式的值由逻辑变元的值计算得出。  以下是常用的逻辑运算符。  ~:表示否定,~P为真当且仅当P为假。  &...
  • sobermineded
  • sobermineded
  • 2018-02-22 23:37:51
  • 46

离散数学-命题逻辑应用举例

  • 2017年10月14日 10:29
  • 873KB
  • 下载

命题逻辑及其形式化系统的局限

前言: 命题逻辑(Propositional Logic)这个概念来自于西方现代数学领域,作为人类理性智慧对世界本质探索的第一次重大飞跃,对人类整个现代文明的推进起到了极其重要的作用。 命题逻辑...
  • u012143360
  • u012143360
  • 2016-01-10 21:38:13
  • 811
    个人资料
    持之以恒
    等级:
    访问量: 936
    积分: 209
    排名: 36万+
    文章存档
    最新评论