1 个不稳定版本
使用旧的 Rust 2015
0.1.0 | 2017 年 8 月 13 日 |
---|
#666 在 机器学习
195KB
4K SLoC
AI_Kit
AI_Kit 旨在成为各种经典 AI 算法的一个依赖项。
核心项目目标是
- 通过构建特性来提供各种算法的便捷和人体工程学接口。
- 通过使用特性标志只构建你需要的内容
- 性能
- 易于理解的实现
以下所有算法(如下文所述)都操作于几个核心特性,BindingsValue
,Unify
,Operation
。
ai_kit
提供 可选数据结构,这些数据结构实现了这些特性,允许所有算法直接使用 - 请参阅 Datum 和 Rule。以下是一些快速示例,随后是更深入的文档。
安装
您可以通过将以下行添加到您的 Cargo.toml 文件中
[dependencies]
ai_kit = "0.1.0"
并将 extern crate ai_kit
添加到您的 crate 根中。
文档
此 README 提供了简介。
API 文档可在 此处 获取
核心概念
当使用此库时,需要了解三个特性和一个结构
Bindings
- 类似于键/值查找,但具有确保两个(或更多)键具有相同值的实用程序。
BindingsValue
- 一个特性,允许数据结构被 Bindings
数据结构使用。
Unify
- 一个特性,允许数据结构可以与另一个相同类型的数据结构统一。
Operation
- 一个特性,用于将一定数量的 Unify
实例映射到一定数量的其他 Unify
。这用于实现 正向 和 反向 推理。
Unify
如果两个数据结构的所有组件都相同,或者至少在字段上有所不同,则可以统一。 Datum 结构实现了 Unify
。 以下 是统一数据的一个示例。
Bindings
当成功时,统一过程返回一个 Bindings
结构体,该结构体将变量名映射到它们的值(如果已知)。它还允许指定两个变量是等价的;在这种情况下,当找到其中一个变量的值时,它被认为是另一个变量的值。
任何实现了 ai_kit::core::BindingsValue
的东西都可以与 Bindings
一起使用;《a href="#readme-datum" rel="ugc noopener">Datum 实现了 BindingsValue
// Example of using the ai_kit::datum::Datum for variable bindings.
extern crate ai_kit;
use ai_kit::core::Bindings;
use ai_kit::datum::Datum;
fn main() {
// Create empty bindings
let bindings : Bindings<Datum> = Bindings::new();
// Set the variables "?x" and "?y" equal to each other
let bindings = bindings
.set_binding(&"?x".to_string(), Datum::Variable("?y".to_string()));
// Set the value of "?x"
let bindings = bindings.set_binding(&"?x".to_string(), Datum::Float(1.0));
// Verify that "?y" now has the same value
assert_eq!(bindings.get_binding(&"?x".to_string()), Some(Datum::Float(1.0)));
}
操作
有时程序具有某些事实,可以从中推断出更多的事实。这是通过 Operation
特性实现的。这用于实现 正向推理 和 规划。正向链推理(也称为Modus Ponens)的例子如下
All men are mortal.
Socrates is a man.
Therefore Socrates is mortal.
规则 结构体实现了 Operation
,我们用它来在 Rust 中执行上述推理。
算法
约束
功能 with-constraint
一个简单且有限的库,用于检查和满足约束。
正向推理
功能 with-forward-inference
正向链推理的实现——本质上这是通过Modus Ponens进行推理。
示例.
规划
功能 with-planner
带有回溯的规划。
谱系
用于表示推导给定推理所采取路径的辅助数据结构和代码。
默认特性格式化实现
上述算法在实现适当核心特性格式(BindingsValue
、Unify
和 Operation
)的任何结构上运行。
ai_kit
提供了实现核心特性格式的默认结构,这应该足以满足许多用例。
数据
功能 with-datum
。
datum::Datum
结构体实现了 BindingsValue
和 Unify
特性。
#[derive(Clone, Debug, Serialize, Deserialize, PartialOrd)]
pub enum Datum {
Nil,
String(String),
Int(i64),
Float(f64),
Variable(String),
Vector(Vec<Datum>),
}
数据实现统一
由于 Datum
实现了 Unify
特性,因此 Datum
可以进行统一。
extern crate ai_kit;
use ai_kit::core::{Bindings, Unify};
use ai_kit::datum::Datum;
fn main() {
let d = Datum::Float(0.0);
let empty_bindings : Bindings<Datum> = Bindings::new();
// These datums are the same, so they can be unified
let bindings = d.unify(&Datum::Float(0.0), &empty_bindings);
assert!(bindings.is_some());
// These datums are not the same, so they cannot be unified
let bindings = d.unify(&Datum::Float(1.0), &empty_bindings);
assert!(bindings.is_none());
// These datums differ, but the second is a variable, so they can be unified
let bindings = d.unify(&Datum::Variable("?x".to_string()), &empty_bindings);
assert!(bindings.is_some());
// The bindings returned by unification so that the variable ?x now has the same value as d!
assert_eq!(bindings.unwrap().get_binding(&"?x".to_string()), Some(d));
}
规则
功能 with-rule
。
rule::Rule
结构体实现了 Operation
特性。
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Rule<T: ConstraintValue, U: Unify<T>> {
pub constraints: Vec<Constraint>,
pub lhs: Vec<U>,
pub rhs: U,
_marker: PhantomData<T>,
}
规则实现操作
extern crate ai_kit;
use ai_kit::datum::Datum;
use ai_kit::infer::InferenceEngine;
use ai_kit::rule::Rule;
use std::marker::PhantomData;
fn main() {
// Encode knowledge about mortality
let rules = vec![
(
"rule_of_mortality".to_string(), // Rules need ids for inferencing
Rule {
constraints: Vec::new(),
lhs: vec![
Datum::Vector(
vec![
Datum::Variable("?x".to_string()),
Datum::String("isa".to_string()),
Datum::String("human".to_string()),
]
)
],
rhs: Datum::Vector(vec![
Datum::Variable("?x".to_string()),
Datum::String("isa".to_string()),
Datum::String("mortal".to_string()),
]),
_marker: PhantomData,
}
),
];
// Setup our initial knowledge about socrates
let facts = vec![
(
"socrates_is_hu``man".to_string(), // Facts need ids for inferencing
Datum::Vector(
vec![
Datum::String("socrates".to_string()),
Datum::String("isa".to_string()),
Datum::String("human".to_string()),
]
)
),
];
// Infer new knowledge!
let mut inf_engine = InferenceEngine::new(
"demo".to_string(),
rules.iter().map(|&(ref id, ref f)| (id, f)).collect(),
facts.iter().map(|&(ref id, ref r)| (id, r)).collect());
let inferences = inf_engine.chain_forward();
assert_eq!(inferences.len(), 1);
}
规划示例
数独求解器
待定
N-Queens 求解器
待定
NLP 解析器
此示例接收一系列单词,以及将单词聚集为短语和句子的规则,并构建单词的有效解析。然后,它在当前工作目录中保存实际构建的目标树的 GraphViz .dot 语法 图为 "parse.dot"。
extern crate ai_kit;
#[macro_use]
extern crate serde_json;
use ai_kit::core::Bindings;
use ai_kit::datum::Datum;
use ai_kit::planner::*;
use ai_kit::rule::Rule;
use std::fs::File;
use std::io::Write;
use std::path;
macro_rules! from_json {
($type: ty, $json: tt) => ({
use serde_json;
let x: $type = serde_json::from_value(json!($json)).expect("Expected json decoding");
x
})
}
#[allow(unused)]
fn main() {
/*
* Inference rules that encode the parts of speech for each word and how to
* compose parts of speech into sentences.
*/
let rules: Vec<Rule<Datum, Datum>> = from_json!(Vec<Rule<Datum, Datum>>, [
// Parts of speech for each word
{"lhs": [{"str": "a"}], "rhs": {"str": "det"}},
{"lhs": [{"str": "the"}], "rhs": {"str": "det"}},
{"lhs": [{"str": "chased"}], "rhs": {"str": "verb"}},
{"lhs": [{"str": "chased"}], "rhs": {"str": "verb"}},
{"lhs": [{"str": "dog"}], "rhs": {"str": "noun"}},
{"lhs": [{"str": "cat"}], "rhs": {"str": "noun"}},
// Building phrases into sentences
{"lhs": [{"str": "det"}, {"str": "noun"}], "rhs": {"str": "np"}},
{"lhs": [{"str": "verb"}, {"str": "np"}], "rhs": {"str": "vp"}},
{"lhs": [{"str": "np"}, {"str": "vp"}], "rhs": {"str": "sen"}}
]);
// Our input data - a series of words
let data: Vec<Datum> = from_json!(Vec<Datum>, [
{"str": "a"},
{"str": "the"},
{"str": "dog"},
{"str": "cat"},
{"str": "chased"}
]);
// Specify that our goal is to construct a sentence from the provided data using the provided rules
let mut planner = Planner::new(&Goal::with_pattern(from_json!(Datum, {"str": "sen"})),
&Bindings::new(),
&PlanningConfig {
max_depth: 5,
max_increments: 50,
// Don't reuse a given piece of data (ie, a word)
reuse_data: false,
},
data.iter().collect(),
rules.iter().collect());
// Construct the first interpretation
let result = planner.next();
assert_eq!(result.is_some(), true);
let (final_goal, bindings) = result.unwrap();
// What are our expected leaves of the goal (ie, the order of parsed sentences)
let expected_leaves: Vec<Datum> = vec![
"a".to_string(),
"dog".to_string(),
"chased".to_string(),
"the".to_string(),
"cat".to_string()
]
.into_iter()
.map(|s| Datum::String(s))
.collect();
// Verify that the leaves of our plan are as expected
assert_eq!(final_goal.gather_leaves(&bindings), expected_leaves);
// Render the plan using graphviz notation
let graphviz_rendering : String = final_goal.render_as_graphviz();
// Save the plan in the current working directory
File::create(path::Path::new(&"parse.dot"))
.and_then(|mut file| file.write_all(graphviz_rendering.as_str().as_bytes()));
}
以下是 "parse.dot" 预期的内容
graph "goal tree 'sen'" {
"'sen' [Actor(8)]" -- "'np' [Actor(6)]";
"'np' [Actor(6)]" -- "'det' [Actor(0)]";
"'det' [Actor(0)]" -- "'a' [Datum(0)]";
"'np' [Actor(6)]" -- "'noun' [Actor(4)]";
"'noun' [Actor(4)]" -- "'dog' [Datum(2)]";
"'sen' [Actor(8)]" -- "'vp' [Actor(7)]";
"'vp' [Actor(7)]" -- "'verb' [Actor(2)]";
"'verb' [Actor(2)]" -- "'chased' [Datum(4)]";
"'vp' [Actor(7)]" -- "'np' [Actor(6)]";
"'np' [Actor(6)]" -- "'det' [Actor(1)]";
"'det' [Actor(1)]" -- "'the' [Datum(1)]";
"'np' [Actor(6)]" -- "'noun' [Actor(5)]";
"'noun' [Actor(5)]" -- "'cat' [Datum(3)]";
}
如果您已本地安装 graphviz,可以将此图转换为 PNG 文件
dot -Tpng parse.dot > parse.png
功能矩阵
一些功能依赖于其他功能。以下表格总结了这些
功能 | 需要 |
---|---|
with-planner |
with-constraint |
with-forward-inference |
with-planner with-constraint |
with-rule |
with-constraint |
with-constraint |
N/A |
with-pedigree |
N/A |
with-datum |
N/A |
怀疑测试
本文件中的示例在构建过程中使用 skeptic 进行测试。
依赖关系
~4.5MB
~96K SLoC