Skip to content
This repository has been archived by the owner on Oct 9, 2023. It is now read-only.

Implement LogicManager and Explanation #46

Merged
merged 64 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
0f63919
fmt
dmikhalin May 31, 2023
79d06f2
fmt
dmikhalin May 31, 2023
02c0051
wip: get_rule(s), put_rule
dmikhalin Jun 1, 2023
ede7983
get_rules isn't async
dmikhalin Jun 2, 2023
80cf00c
"rules do not contain" step
dmikhalin Jun 2, 2023
d10f36f
Explanations
dmikhalin Jun 5, 2023
e1064fc
`rules are` step
dmikhalin Jun 5, 2023
6621ca9
Add `inferred` field
dmikhalin Jun 7, 2023
2931c5a
explanation test (wip)
dmikhalin Jun 7, 2023
87cc6ca
PartialEq trait for Concept
dmikhalin Jun 8, 2023
68f82a1
test_disjunction_explainable
dmikhalin Jun 8, 2023
1a9b4f2
Empty Explainables -> None
dmikhalin Jun 8, 2023
189a2d4
test_relation_explainable
dmikhalin Jun 8, 2023
04dce46
test_relation_explainable_multiple_ways
dmikhalin Jun 8, 2023
ff2bbf5
test_has_explicit_explainable_two_ways
dmikhalin Jun 8, 2023
ac4e714
fmt
dmikhalin Jun 8, 2023
6665d13
Cleanup
dmikhalin Jun 8, 2023
77488de
fmt
dmikhalin Jun 8, 2023
ebddff0
Run logic tests on Cluster
dmikhalin Jun 8, 2023
b688097
127.0.0.1 -> localhost in the Cluster connection
dmikhalin Jun 8, 2023
165489f
Reasoner steps
dmikhalin Jun 9, 2023
56af7ee
Fix imports after rebase
dmikhalin Jun 9, 2023
2bc131e
rename logic.rs to logic_manager.rs
dmikhalin Jun 9, 2023
3891d3a
Refactoring
dmikhalin Jun 13, 2023
113b2c3
Cleanup
dmikhalin Jun 13, 2023
6372a67
Refactor
dmikhalin Jun 13, 2023
a5f38e2
Option<Explainables> -> Empty Explainables
dmikhalin Jun 13, 2023
12f811a
Default Explainables
dmikhalin Jun 14, 2023
a704652
Remove concepts_to_vec()
dmikhalin Jun 14, 2023
8420aee
inferred -> is_inferred
dmikhalin Jun 14, 2023
7cd4ed9
Deconstruction + fmt
dmikhalin Jun 14, 2023
9bc06a9
RuleRequest, RuleResponse
dmikhalin Jun 14, 2023
a09f3a3
logic.logic_manager -> transaction.logic.manager
dmikhalin Jun 14, 2023
2817df9
RuleAPI
dmikhalin Jun 14, 2023
1e79084
BDD steps for rules
dmikhalin Jun 14, 2023
4218ffa
fmt
dmikhalin Jun 14, 2023
879ace8
Rules BDD tests
dmikhalin Jun 14, 2023
b3ad787
Extract reasoner tests
dmikhalin Jun 14, 2023
42f488f
Reordering
dmikhalin Jun 14, 2023
1b2169e
Remove redundant clone()
dmikhalin Jun 15, 2023
2b90c9a
Refactoring
dmikhalin Jun 15, 2023
1342e75
Fix rebase
dmikhalin Jun 15, 2023
c83c108
typeql BDD test regrouping
dmikhalin Jun 15, 2023
0a6110c
Add comment to do_nothing()
dmikhalin Jun 15, 2023
c6094e0
fmt
dmikhalin Jun 15, 2023
8a67c03
Fix error types
dmikhalin Jun 15, 2023
7f681d9
Remove redundant check
dmikhalin Jun 15, 2023
3c200c8
explainables_count -> 1
dmikhalin Jun 15, 2023
c7ce907
Simplify
dmikhalin Jun 19, 2023
84d902c
Cleanup
dmikhalin Jun 19, 2023
4dc3727
Refactor
dmikhalin Jun 19, 2023
63a54a4
Separate reasoner tests
dmikhalin Jun 19, 2023
7a3ae3e
word -> label
dmikhalin Jun 19, 2023
0e78574
str in step table identifiers
dmikhalin Jun 20, 2023
59f6022
Remove redundant map_err
dmikhalin Jun 20, 2023
38d5a76
Refactor
dmikhalin Jun 20, 2023
a9854e2
Refactor
dmikhalin Jun 20, 2023
6a7ef99
Remove trimming
dmikhalin Jun 21, 2023
7506acc
Refactor
dmikhalin Jun 21, 2023
cc7ca76
fmt
dmikhalin Jun 21, 2023
fd0cc10
Simplification
dmikhalin Jun 21, 2023
006972c
TransactionRequest reordering
dmikhalin Jun 22, 2023
f6ec58d
Tests refactoring
dmikhalin Jun 22, 2023
3f2bb57
Check only one db existance
dmikhalin Jun 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dependencies/vaticle/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def vaticle_typedb_behaviour():
git_repository(
name = "vaticle_typedb_behaviour",
remote = "https://github.com/vaticle/typedb-behaviour",
commit = "d4947828f570853b71f0eb8aefd34af7b5a485fb",
commit = "d4947828f570853b71f0eb8aefd34af7b5a485fb", # sync-marker: do not remove this comment, this is used for sync-dependencies by @vaticle_typedb_behaviour
)

def vaticle_typeql():
Expand Down
42 changes: 27 additions & 15 deletions src/answer/concept_map.rs
dmikhalin marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ use std::{

use crate::concept::Concept;

#[derive(Debug)]
#[derive(Clone, Debug, PartialEq)]
pub struct ConceptMap {
pub map: HashMap<String, Concept>,
pub explainables: Explainables,
}

impl ConceptMap {
Expand All @@ -39,20 +40,6 @@ impl ConceptMap {
pub fn concepts(&self) -> impl Iterator<Item = &Concept> {
self.map.values()
}

pub fn concepts_to_vec(&self) -> Vec<&Concept> {
self.concepts().collect::<Vec<&Concept>>()
}
}

impl Clone for ConceptMap {
fn clone(&self) -> Self {
let mut map = HashMap::with_capacity(self.map.len());
for (k, v) in &self.map {
map.insert(k.clone(), v.clone());
}
Self { map }
}
}
dmikhalin marked this conversation as resolved.
Show resolved Hide resolved

impl From<ConceptMap> for HashMap<String, Concept> {
Expand All @@ -77,3 +64,28 @@ impl IntoIterator for ConceptMap {
self.map.into_iter()
}
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct Explainables {
pub relations: HashMap<String, Explainable>,
pub attributes: HashMap<String, Explainable>,
pub ownerships: HashMap<(String, String), Explainable>,
}

impl Explainables {
pub fn is_empty(&self) -> bool {
self.relations.is_empty() && self.attributes.is_empty() && self.ownerships.is_empty()
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct Explainable {
pub conjunction: String,
pub id: i64,
}

impl Explainable {
pub(crate) fn new(conjunction: String, id: i64) -> Self {
Self { conjunction, id }
}
}
7 changes: 5 additions & 2 deletions src/answer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
* under the License.
*/

mod concept_map;
pub mod concept_map;
mod concept_map_group;
mod numeric;
mod numeric_group;

pub use self::{
concept_map::ConceptMap, concept_map_group::ConceptMapGroup, numeric::Numeric, numeric_group::NumericGroup,
concept_map::{ConceptMap, Explainable, Explainables},
concept_map_group::ConceptMapGroup,
numeric::Numeric,
numeric_group::NumericGroup,
};
2 changes: 2 additions & 0 deletions src/common/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ error_messages! { ConnectionError
9: "Missing field in message received from server: '{}'.",
UnknownRequestId(RequestID) =
10: "Received a response with unknown request id '{}'",
InvalidResponseField(&'static str) =
11: "Invalid field in message received from server: '{}'.",
ClusterUnableToConnect(String) =
12: "Unable to connect to TypeDB Cluster. Attempted connecting to the cluster members, but none are available: '{}'.",
ClusterReplicaNotPrimary() =
Expand Down
2 changes: 1 addition & 1 deletion src/concept/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub use self::{
},
};

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq)]
pub enum Concept {
RootThingType(RootThingType),

Expand Down
3 changes: 3 additions & 0 deletions src/concept/thing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,22 @@ impl Thing {
pub struct Entity {
pub iid: IID,
pub type_: EntityType,
pub is_inferred: bool,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Relation {
pub iid: IID,
pub type_: RelationType,
pub is_inferred: bool,
}

#[derive(Clone, Debug, PartialEq)]
pub struct Attribute {
pub iid: IID,
pub type_: AttributeType,
pub value: Value,
pub is_inferred: bool,
}

#[derive(Clone, Debug, PartialEq)]
Expand Down
34 changes: 33 additions & 1 deletion src/connection/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use std::time::Duration;
use tokio::sync::mpsc::UnboundedSender;
use tonic::Streaming;
use typedb_protocol::transaction;
use typeql_lang::pattern::{Conjunction, Variable};

use crate::{
answer::{ConceptMap, ConceptMapGroup, Numeric, NumericGroup},
Expand All @@ -32,6 +33,7 @@ use crate::{
Annotation, Attribute, AttributeType, Entity, EntityType, Relation, RelationType, RoleType, SchemaException,
Thing, ThingType, Transitivity, Value, ValueType,
},
logic::{Explanation, Rule},
Options, SessionType, TransactionType,
};

Expand Down Expand Up @@ -108,6 +110,8 @@ pub(super) enum TransactionRequest {
RoleType(RoleTypeRequest),
Thing(ThingRequest),
Stream { request_id: RequestID },
Rule(RuleRequest),
Logic(LogicRequest),
dmikhalin marked this conversation as resolved.
Show resolved Hide resolved
}

#[derive(Debug)]
Expand All @@ -120,6 +124,8 @@ pub(super) enum TransactionResponse {
ThingType(ThingTypeResponse),
RoleType(RoleTypeResponse),
Thing(ThingResponse),
Rule(RuleResponse),
Logic(LogicResponse),
}

#[derive(Debug)]
Expand Down Expand Up @@ -152,7 +158,7 @@ pub(super) enum QueryResponse {

MatchAggregate { answer: Numeric },

Explain {}, // TODO: explanations
Explain { answers: Vec<Explanation> },

MatchGroup { answers: Vec<ConceptMapGroup> },
MatchGroupAggregate { answers: Vec<NumericGroup> },
Expand Down Expand Up @@ -457,3 +463,29 @@ pub(super) enum ThingResponse {

AttributeGetOwners { owners: Vec<Thing> },
}

#[derive(Debug)]
pub(super) enum RuleRequest {
Delete { label: String },
SetLabel { current_label: String, new_label: String },
}

#[derive(Debug)]
pub(super) enum RuleResponse {
Delete,
SetLabel,
}

#[derive(Debug)]
pub(super) enum LogicRequest {
PutRule { label: String, when: Conjunction, then: Variable },
GetRule { label: String },
GetRules,
}

#[derive(Debug)]
pub(super) enum LogicResponse {
PutRule { rule: Rule },
GetRule { rule: Rule },
GetRules { rules: Vec<Rule> },
}
96 changes: 72 additions & 24 deletions src/connection/network/proto/concept.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,21 @@ use typedb_protocol::{
r#type::{annotation, Annotation as AnnotationProto, Transitivity as TransitivityProto},
thing, thing_type, Attribute as AttributeProto, AttributeType as AttributeTypeProto, Concept as ConceptProto,
ConceptMap as ConceptMapProto, ConceptMapGroup as ConceptMapGroupProto, Entity as EntityProto,
EntityType as EntityTypeProto, Numeric as NumericProto, NumericGroup as NumericGroupProto,
EntityType as EntityTypeProto, Explainable as ExplainableProto, Explainables as ExplainablesProto,
Explanation as ExplanationProto, Numeric as NumericProto, NumericGroup as NumericGroupProto,
Relation as RelationProto, RelationType as RelationTypeProto, RoleType as RoleTypeProto, Thing as ThingProto,
ThingType as ThingTypeProto,
};

use super::{FromProto, IntoProto, TryFromProto};
use crate::{
answer::{ConceptMap, ConceptMapGroup, Numeric, NumericGroup},
answer::{ConceptMap, ConceptMapGroup, Explainable, Explainables, Numeric, NumericGroup},
concept::{
Annotation, Attribute, AttributeType, Concept, Entity, EntityType, Relation, RelationType, RoleType,
RootThingType, ScopedLabel, Thing, ThingType, Transitivity, Value, ValueType,
},
error::{ConnectionError, InternalError},
logic::{Explanation, Rule},
Result,
};

Expand Down Expand Up @@ -97,11 +99,11 @@ impl TryFromProto<ConceptMapGroupProto> for ConceptMapGroup {

impl TryFromProto<ConceptMapProto> for ConceptMap {
fn try_from_proto(proto: ConceptMapProto) -> Result<Self> {
let mut map = HashMap::with_capacity(proto.map.len());
for (k, v) in proto.map {
map.insert(k, Concept::try_from_proto(v)?);
}
Ok(Self { map })
let ConceptMapProto { map: map_proto, explainables: explainables_proto } = proto;
let map = map_proto.into_iter().map(|(k, v)| Concept::try_from_proto(v).map(|v| (k, v))).try_collect()?;
let explainables = explainables_proto
.ok_or::<ConnectionError>(ConnectionError::MissingResponseField("explainables").into())?;
Ok(Self { map, explainables: Explainables::from_proto(explainables) })
}
}

Expand Down Expand Up @@ -277,66 +279,64 @@ impl IntoProto<ThingProto> for Thing {

impl TryFromProto<EntityProto> for Entity {
fn try_from_proto(proto: EntityProto) -> Result<Self> {
let EntityProto { iid, entity_type, inferred: _ } = proto;
let EntityProto { iid, entity_type, inferred } = proto;
Ok(Self {
iid: iid.into(),
type_: EntityType::from_proto(entity_type.ok_or(ConnectionError::MissingResponseField("entity_type"))?),
is_inferred: inferred,
})
}
}

impl IntoProto<EntityProto> for Entity {
fn into_proto(self) -> EntityProto {
EntityProto {
iid: self.iid.into(),
entity_type: Some(self.type_.into_proto()),
inferred: false, // FIXME
}
let Self { iid, type_, is_inferred } = self;
EntityProto { iid: iid.into(), entity_type: Some(type_.into_proto()), inferred: is_inferred }
}
}

impl TryFromProto<RelationProto> for Relation {
fn try_from_proto(proto: RelationProto) -> Result<Self> {
let RelationProto { iid, relation_type, inferred: _ } = proto;
let RelationProto { iid, relation_type, inferred } = proto;
Ok(Self {
iid: iid.into(),
type_: RelationType::from_proto(
relation_type.ok_or(ConnectionError::MissingResponseField("relation_type"))?,
),
is_inferred: inferred,
})
}
}

impl IntoProto<RelationProto> for Relation {
fn into_proto(self) -> RelationProto {
RelationProto {
iid: self.iid.into(),
relation_type: Some(self.type_.into_proto()),
inferred: false, // FIXME
}
let Self { iid, type_, is_inferred } = self;
RelationProto { iid: iid.into(), relation_type: Some(type_.into_proto()), inferred: is_inferred }
}
}

impl TryFromProto<AttributeProto> for Attribute {
fn try_from_proto(proto: AttributeProto) -> Result<Self> {
let AttributeProto { iid, attribute_type, value, inferred: _ } = proto;
let AttributeProto { iid, attribute_type, value, inferred } = proto;
Ok(Self {
iid: iid.into(),
type_: AttributeType::try_from_proto(
attribute_type.ok_or(ConnectionError::MissingResponseField("attribute_type"))?,
)?,
value: Value::try_from_proto(value.ok_or(ConnectionError::MissingResponseField("value"))?)?,
is_inferred: inferred,
})
}
}

impl IntoProto<AttributeProto> for Attribute {
fn into_proto(self) -> AttributeProto {
let Self { iid, type_, value, is_inferred } = self;
AttributeProto {
iid: self.iid.into(),
attribute_type: Some(self.type_.into_proto()),
value: Some(self.value.into_proto()),
inferred: false, // FIXME
iid: iid.into(),
attribute_type: Some(type_.into_proto()),
value: Some(value.into_proto()),
inferred: is_inferred,
}
}
}
Expand Down Expand Up @@ -369,3 +369,51 @@ impl IntoProto<ValueProto> for Value {
}
}
}

impl FromProto<ExplainablesProto> for Explainables {
fn from_proto(proto: ExplainablesProto) -> Self {
let ExplainablesProto {
relations: relations_proto,
attributes: attributes_proto,
ownerships: ownerships_proto,
} = proto;
let relations = relations_proto.into_iter().map(|(k, v)| (k, Explainable::from_proto(v))).collect();
let attributes = attributes_proto.into_iter().map(|(k, v)| (k, Explainable::from_proto(v))).collect();
let mut ownerships = HashMap::new();
for (k1, owned) in ownerships_proto {
for (k2, v) in owned.owned {
ownerships.insert((k1.clone(), k2), Explainable::from_proto(v));
}
}

Self { relations, attributes, ownerships }
}
}

impl FromProto<ExplainableProto> for Explainable {
fn from_proto(proto: ExplainableProto) -> Self {
let ExplainableProto { conjunction, id } = proto;
Self::new(conjunction, id)
}
}

impl TryFromProto<ExplanationProto> for Explanation {
fn try_from_proto(proto: ExplanationProto) -> Result<Self> {
let ExplanationProto { rule, conclusion, condition, var_mapping } = proto;
let mut variable_mapping = HashMap::with_capacity(var_mapping.len());
for (k, v) in var_mapping {
variable_mapping.insert(k, v.vars);
}

Ok(Self {
rule: Rule::try_from_proto(rule.ok_or(ConnectionError::MissingResponseField("rule"))?)?,
conclusion: ConceptMap::try_from_proto(
conclusion.ok_or(ConnectionError::MissingResponseField("conclusion"))?,
)?,
condition: ConceptMap::try_from_proto(
condition.ok_or(ConnectionError::MissingResponseField("condition"))?,
)?,
variable_mapping,
})
}
}
Loading