Fix opposite_eq method.
Simplify method in Simplify trait. Fix distributive law. Response for the simplify endpoint. HTTP client. camelCase and SCREAMING_SNAKE_CASE for struct and enum
This commit is contained in:
parent
c4393e94bf
commit
9cb0fa0a59
8
http/common.js
Normal file
8
http/common.js
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Encode the given string as a URI component, and set the request variable "expression" to the result.
|
||||
* @param {string} expression
|
||||
* @returns {void}
|
||||
*/
|
||||
export function expression(expression) {
|
||||
request.variables.set("expression", encodeURIComponent(expression))
|
||||
}
|
10
http/http-client.env.json
Normal file
10
http/http-client.env.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"dev": {
|
||||
"expression": "",
|
||||
"url": "http://localhost:8000"
|
||||
},
|
||||
"prod": {
|
||||
"expression": "",
|
||||
"url": "https://api.martials.no/simplify-truths"
|
||||
}
|
||||
}
|
29
http/simplify.http
Normal file
29
http/simplify.http
Normal file
@ -0,0 +1,29 @@
|
||||
### GET Atomic Expression
|
||||
GET {{url}}/simplify/A
|
||||
|
||||
### GET And Expression
|
||||
< {%
|
||||
import {expression} from './common.js';
|
||||
|
||||
expression("A & B")
|
||||
%}
|
||||
GET {{url}}/simplify/{{expression}}
|
||||
|
||||
### GET Or Expression
|
||||
< {%
|
||||
import {expression} from "./common";
|
||||
|
||||
expression("A | B")
|
||||
%}
|
||||
GET {{url}}/simplify/{{expression}}
|
||||
|
||||
### GET Not Expression
|
||||
GET {{url}}/simplify/!A
|
||||
|
||||
### GET Implication Expression
|
||||
< {%
|
||||
import {expression} from "./common";
|
||||
|
||||
expression("A => B")
|
||||
%}
|
||||
GET {{url}}/simplify/{{expression}}
|
@ -1,4 +1,5 @@
|
||||
use std::fmt::Display;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::expressions::operator::BinaryOperator;
|
||||
use crate::parsing::expression_parser::parse_expression;
|
||||
@ -7,7 +8,8 @@ pub trait OppositeEq {
|
||||
fn opposite_eq(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Expression {
|
||||
Not(Box<Expression>),
|
||||
Binary(Box<Expression>, BinaryOperator, Box<Expression>),
|
||||
@ -40,8 +42,8 @@ impl OppositeEq for Expression {
|
||||
fn opposite_eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Expression::Not(_), Expression::Not(_)) => false,
|
||||
(Expression::Not(_), _) => true,
|
||||
(_, Expression::Not(_)) => true,
|
||||
(Expression::Not(left), right) => left.as_ref() == right,
|
||||
(left, Expression::Not(right)) => left == right.as_ref(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,9 @@
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
pub enum BinaryOperator {
|
||||
Implication,
|
||||
Or,
|
||||
And,
|
||||
}
|
||||
|
||||
impl From<BinaryOperator> for &str {
|
||||
fn from(op: BinaryOperator) -> Self {
|
||||
match op {
|
||||
BinaryOperator::Implication => "=>",
|
||||
BinaryOperator::Or => "|",
|
||||
BinaryOperator::And => "&",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use crate::expressions::expression::{Expression, OppositeEq};
|
||||
use crate::expressions::operator::BinaryOperator;
|
||||
|
||||
pub trait Simplify {
|
||||
fn simplify(&self) -> Self;
|
||||
fn elimination_of_implication(&self) -> Self;
|
||||
fn double_negation_elimination(&self) -> Self;
|
||||
fn de_morgans_laws(&self) -> Self;
|
||||
@ -12,6 +13,16 @@ pub trait Simplify {
|
||||
}
|
||||
|
||||
impl Simplify for Expression {
|
||||
// TODO test and define order of operations
|
||||
fn simplify(&self) -> Self {
|
||||
self.elimination_of_implication()
|
||||
.de_morgans_laws()
|
||||
.absorption_law()
|
||||
// .associative_law()
|
||||
.distribution_law()
|
||||
.double_negation_elimination()
|
||||
// .commutative_law()
|
||||
}
|
||||
/// Eliminate the implication operator from the expression.
|
||||
/// This is done by replacing `a ➔ b` with `¬a ⋁ b`.
|
||||
fn elimination_of_implication(&self) -> Self {
|
||||
@ -194,7 +205,7 @@ impl Simplify for Expression {
|
||||
let right = right.distribution_law();
|
||||
binary!(left, *operator, right)
|
||||
}
|
||||
Expression::Not(expr) => expr.distribution_law(),
|
||||
Expression::Not(expr) => not!(expr.distribution_law()),
|
||||
atomic => atomic.clone(),
|
||||
}
|
||||
}
|
||||
@ -208,6 +219,18 @@ impl Simplify for Expression {
|
||||
mod tests {
|
||||
use crate::expressions::simplify::Simplify;
|
||||
|
||||
#[test]
|
||||
fn test_simplify() {
|
||||
let expression = eval!("a" => "b").simplify();
|
||||
assert_eq!(expression, or!(not!(atomic!("a")), atomic!("b")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_implication_and_de_morgans() {
|
||||
let expression = implies!(and!(not!(atomic!("a")), atomic!("b")), atomic!("c")).simplify();
|
||||
assert_eq!(expression, or!(or!(atomic!("a"), not!(atomic!("b"))), atomic!("c")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_elimination_of_implication() {
|
||||
let expression = eval!("a" => "b").elimination_of_implication();
|
||||
@ -349,4 +372,10 @@ mod tests {
|
||||
let expression = or!(atomic!("a"), and!(atomic!("b"), atomic!("c"))).distribution_law();
|
||||
assert_eq!(expression, and!(or!(atomic!("a"), atomic!("b")), or!(atomic!("a"), atomic!("c"))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_distributive_law_nested_not() {
|
||||
let expression = and!(atomic!("a"), not!(or!(atomic!("b"), atomic!("c")))).distribution_law();
|
||||
assert_eq!(expression, and!(atomic!("a"), not!(or!(atomic!("b"), atomic!("c")))))
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
use axum::{Router, routing::get};
|
||||
use axum::{Json, Router, routing::get};
|
||||
use axum::extract::{Path, Query};
|
||||
use serde::Deserialize;
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::expressions::expression::Expression;
|
||||
use crate::expressions::simplify::Simplify;
|
||||
use crate::language::{AcceptLanguage, Language};
|
||||
|
||||
pub fn router() -> Router<()> {
|
||||
@ -23,13 +27,32 @@ struct QueryOptions {
|
||||
lang: Language,
|
||||
#[serde(default = "default_true")]
|
||||
simplify: bool,
|
||||
#[serde(default)]
|
||||
#[serde(default = "default_true")]
|
||||
case_sensitive: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SimplifyResponse {
|
||||
before: String,
|
||||
after: String,
|
||||
order_of_operations: Vec<String>,
|
||||
expression: Expression,
|
||||
}
|
||||
|
||||
// TODO
|
||||
async fn simplify(Path(path): Path<String>, query: Query<QueryOptions>, accept_language: Option<AcceptLanguage>) -> String {
|
||||
format!("Path: {}, Query: {:?}, Accept-language header: {:?}", path, query, accept_language)
|
||||
async fn simplify(Path(path): Path<String>, query: Query<QueryOptions>, accept_language: Option<AcceptLanguage>) -> Response {
|
||||
if let Ok(expression) = Expression::try_from(path.as_str()) {
|
||||
let simplified = expression.simplify();
|
||||
Json(SimplifyResponse {
|
||||
before: expression.to_string(),
|
||||
after: simplified.to_string(),
|
||||
order_of_operations: vec![], // TODO
|
||||
expression: simplified,
|
||||
}).into_response()
|
||||
} else {
|
||||
(StatusCode::BAD_REQUEST, "Invalid expression").into_response()
|
||||
}
|
||||
}
|
||||
|
||||
async fn simplify_and_table() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user