Mathematical formulas as objects in C++.

huangapple go评论71阅读模式
英文:

Mathematical formulas as objects in c++

问题

Here is the translated code without the code comments and the parts you requested not to translate:

#include <iostream>
using namespace std;

class connective
{
    int val;

public:
    connective()
    {
    }

    ~connective()
    {
    }

    connective(int x)
    {
        val = x;
    }

    int value()
    {
        return val;
    }

    void assign(int x)
    {
        val = x;
    }

    string label()
    {
        if (val == -1)
            return "¬";

        if (val == 0)
            return "";

        if (val == 1)
            return u8"∧";

        if (val == 2)
            return u8"∨";

        if (val == 3)
            return "→";

        else
            return "↔";
    }
};

class formula
{
    connective con;

    formula *f, *g;

public:
    formula()
    {
    }

    ~formula()
    {
    }

    formula(int n, formula* p, formula* q)
    {
        con.assign(n);

        f = p;
        g = q;
    }

    formula(int n, formula* p)
    {
        con.assign(n);

        f = p;
    }

    virtual void print()
    {
        if (con.value() == -1)
        {
            cout << con.label();
            f->print();
        }

        else
        {
            cout << "(";

            f->print();

            cout << " " << con.label() << " ";

            g->print();

            cout << ")";
        }
    }

    virtual char type()
    {
        return 'F';
    }

    formula operator and(formula* x)
    {
        return formula(1, this, x);
    }

    formula operator or(formula* x)
    {
        return formula(2, this, x);
    }

    formula* left()
    {
        return f;
    }

    formula* right()
    {
        return g;
    }

    formula operator not()
    {
        return formula(-1, this);
    }
};

class variable : public formula
{
    char symbol;

public:
    variable() : formula()
    {
    }

    ~variable()
    {
    }

    variable(char c) : formula()
    {
        symbol = c;
    }

    char label()
    {
        return symbol;
    }

    void print()
    {
        cout << symbol;
    }

    char type()
    {
        return 'C';
    }

    bool operator==(variable x)
    {
        return x.label() == symbol;
    }
};

I've translated the relevant C++ code for your propositional logic implementation while keeping the structure of your classes and methods intact.

英文:

I am trying to implement propositional logic in c++. Two issues, the first one is I am having issues with creating the implication and if and only if operators. The second issue I have is implementing the assignment class. An assignment should be an object that given a formula determines whether it is true under that assignment. The thing is the connectors are implemented as a class and then I overload the operator inside formula. I would like to make the connector class into an operator that works on formulas. Also I am not sure if there is a solution to for this but I would like to not have to use pointers everywhere to avoid slicing variables into formulas. Any help is appreciated.

// History
// Created: Oscar Grove 28/12/2021
//
// Modified: Oscar Grove 30/12/2021
//           Oscar Grove 22/05/2023
#include &lt;iostream&gt;
using namespace std;
class connective
{
int val;
public:
connective ()
{
}
~connective ()
{
}
connective (int x)
{
val = x;
}
int value ()
{
return val;
}
void assign (int x)
{
val = x;
}
string label ()
{
if (val == -1)
return &quot;&#172;&quot;;
if (val == 0)
return &quot;&quot;;
if (val == 1)
return u8&quot;\u2227&quot;;
if (val == 2)
return u8&quot;\u2228&quot;;
if (val == 3)
return &quot;-&gt;&quot;;
else
return &quot;&lt;-&gt;&quot;;
}
};
class formula
{
connective con;
formula *f, *g;
public:
formula ()
{
}
~formula ()
{
}
formula (int n, formula* p, formula* q)
{
con.assign (n);
f = p;
g = q;
}
formula (int n, formula* p)
{
con.assign (n);
f = p;
}
virtual void print ()
{
if (con.value () == -1)
{
cout &lt;&lt; con.label();
f -&gt; print ();
}
else
{
cout &lt;&lt; &quot;(&quot;;
f -&gt; print ();
cout &lt;&lt; &quot; &quot; &lt;&lt; con.label () &lt;&lt; &quot; &quot;;
g -&gt; print ();
cout &lt;&lt; &quot;)&quot;; 
}
}
virtual char type ()
{
return &#39;F&#39;;
}
formula operator and (formula* x)
{
return formula (1, this, x);
}
formula operator or (formula* x)
{
return formula (2, this, x);
}
formula* left ()
{
return f;
}
formula* right ()
{
return g;
}
formula operator not ()
{
return formula (-1, this);
}
/*formula operator &gt;&gt; (formula* x)
{
return formula (3, this x);
}
formula operator &lt;&gt; (formula* x)
{
return formula (4, this, x);
}*/
};
class variable: public formula
{
char symbol;
public:
variable () : formula ()
{
}
~variable ()
{
}
variable (char c) : formula ()
{
symbol = c;
}
char label ()
{
return symbol;
}
void print ()
{
cout &lt;&lt; symbol;
}
char type ()
{
return &#39;C&#39;;
}
bool operator == (variable x)
{
return x.label () == symbol;
}
};
// History
// Created: Oscar Grove 30/12/2021
//
// Modified: Oscar Grove 22/05/2023
#include &quot;formula.h&quot;
using namespace std;
class set
{
set *node, *left, *right;	
void add (variable x)
{
}
void remove (variable x)
{
}
public:
set ()
{
}
~set ()
{
}
bool contains (set* s)
{
if (node == NULL)
return false;
if (*s == *node)
return true;
return left -&gt; contains (s) or right -&gt; contains (s);
}
/*set operator + (set* a, set* b)
{
}
set operator - (set* a, set* b)
{
}
set union ()
{
}*/
};
class assignment
{
set S;
bool applied (formula* F)
{
if (F -&gt; type () == &#39;C&#39;)
return 1;
return applied (F -&gt; left ())
}
}
// History
// Created: Oscar Grove 30/12/2021
//
// Modified: Oscar Grove 22/05/2023
#include &quot;formula.h&quot;
using namespace std;
int main ()
{
variable a (&#39;A&#39;), b (&#39;B&#39;), c (&#39;C&#39;), d (&#39;D&#39;);
formula F = a and &amp;b, G = not c, X (3, &amp;F, &amp;G);
G.left () -&gt; type ();
X.print ();
cout &lt;&lt; endl;
}

I am aware set is not yet implemented but it is not relevant to my question.

I tried creating a constructor for a formula pointer but that did not work out. Regarding the assignment class I could try and do a switch to go case by case but my objective would be to be able to write expressions as mathematically as possible so that the functioning of an object is as close as possible to the definition of the mathematical object.

答案1

得分: 2

我已翻译您提供的内容:

我写过几种类似的小语言(虽然不是特定的命题逻辑),并且提出了一种使用`std::variant`来存储不同类型的标准起始设计,以及在构建表达式时依赖于`std::shared_ptr`(尽管如果您不打算对常见子表达式进行分组,也可以使用`std::unique_ptr`)的连接性。

您提到不想使用指针,但我认为这是在运行时表示构建和操作的表达式的最佳选项。特别是如果您希望对表达式进行优化和其他转换。从使用的角度来看,使用`std::shared_ptr`与使用对象一样清晰。

我勾勒了一些代码,并且这里是一个使用示例:

用法
-----
```c++
使用std::cout, std::endl;

int main(int argc, const char *argv[]) {
    auto f = !(ptrue() || "A"_v);
    auto g = simplify(f);
    cout << f << endl;
    cout << g << endl;
    return 0;
}

输出

¬ (  A)

如果这是您想要作为一个小型开源项目进行的事情,我会有兴趣提供帮助。

代码

(以下是您提供的代码)


希望这些翻译对您有所帮助。
<details>
<summary>英文:</summary>
I have written several small languages like this (although not Propositional Logic in particular) and have come up with a somewhat standard starting design that uses a `std::variant` to store the different types and relies on `std::shared_ptr` (although you could also use `std::unique_ptr` if you do not intend to group common sub-expressions) for the connectivity when building expressions.
You mentioned not wanting to use pointers, but I think it is the best option for representing expressions that are built and manipulated at runtime. This is especially true if you want to do optimizations and other transformations on the expression. From the usage perspective, using `std::shared_ptr` is as clean as using objects.
I sketched out some code and here is a usage example:
Usage
-----
```c++
using std::cout, std::endl;
int main(int argc, const char *argv[]) {
auto f = !(ptrue() || &quot;A&quot;_v);
auto g = simplify(f);
cout &lt;&lt; f &lt;&lt; endl;
cout &lt;&lt; g &lt;&lt; endl;
return 0;
}

Output

&#172; (  A)

If this is something you'd like to work on as a small open source project, I would be interesting in helping out.

Code

#include &lt;variant&gt;
#include &lt;iostream&gt;

// Pattern match a `std::variant` derived type against its contained type.
//
// match helpers
namespace detail {
template&lt;class... Ts&gt; struct overloaded : Ts... { using Ts::operator()...; };
template&lt;class... Ts&gt; overloaded(Ts...) -&gt; overloaded&lt;Ts...&gt;;
}; // detail

template&lt;class T, class... Us&gt;
auto match(T&amp;&amp; variant, Us&amp;&amp;... handlers) {
    return std::visit(detail::overloaded{std::forward&lt;Us&gt;(handlers)...}, std::forward&lt;T&gt;(variant));
}

// Logic symobls using unicode.
namespace uch {
inline constexpr auto True = &quot;\u22a4&quot;;
inline constexpr auto False = &quot;\u22a5&quot;;
inline constexpr auto Negation = &quot;\u00ac&quot;;
inline constexpr auto Conjunction = &quot;\u2227&quot;;
inline constexpr auto Disjunction = &quot;\u2228&quot;;
inline constexpr auto Implies = &quot;\u2192&quot;;
inline constexpr auto Equivalence = &quot;\u2194&quot;;
};

// Declare the Proposition types.
struct Variable;
struct True;
struct False;
struct Negation;
struct Conjunction;
struct Disjunction;
struct Implies;
struct Equivalence;

// The variant type that holds a Proposition.
using Base = std::variant&lt;
    Variable,
    True,
    False,
    Negation,
    Conjunction,
    Disjunction,
    Implies,
    Equivalence
    &gt;;

// All Proposition&#39;s are shared pointers.
using Proposition = std::shared_ptr&lt;Base&gt;;

// Define the Proposition types.
struct Variable {
    Variable(const std::string&amp; v) : name(v) { }
    std::string name;
};

struct True { };

struct False { };

struct Negation {
    Negation(Proposition p) : child(p) { }
    Proposition child;
};

struct Conjunction {
    Conjunction(Proposition p, Proposition q) : left(p), right(q) { }
    Proposition left, right;
};

struct Disjunction {
    Disjunction(Proposition p, Proposition q) : left(p), right(q) { }
    Proposition left, right;
};
struct Implies {
    Implies(Proposition p, Proposition q) : left(p), right(q) { }
    Proposition left, right;
};

struct Equivalence {
    Equivalence(Proposition p, Proposition q) : left(p), right(q) { }
    Proposition left, right;
};

// Helpers for creating Propositions.
template&lt;class T, class... Args&gt;
Proposition proposition(Args... args) {
    return std::make_shared&lt;Base&gt;(T{args...});
}

Proposition variable(const std::string&amp; v) {
    return proposition&lt;Variable&gt;(v);
}

Proposition ptrue() {
    return proposition&lt;True&gt;();
}

Proposition pfalse() {
    return proposition&lt;False&gt;();
}

Proposition negation(Proposition child) {
    return proposition&lt;Negation&gt;(child);
}

Proposition conjunction(Proposition l, Proposition r) {
    return proposition&lt;Conjunction&gt;(l, r);
}

Proposition disjunction(Proposition l, Proposition r) {
    return proposition&lt;Disjunction&gt;(l, r);
}

Proposition implies(Proposition l, Proposition r) {
    return proposition&lt;Implies&gt;(l, r);
}

Proposition equivalence(Proposition l, Proposition r) {
    return proposition&lt;Equivalence&gt;(l, r);
}

// Variable literals.
Proposition operator &quot;&quot;_v(const char *s, size_t) {
    std::string str(s);
    return variable(str);
}

// Use the builtin operators to construct Propositions.
auto operator!(Proposition p) {
    return negation(p);
}

auto operator&amp;&amp;(Proposition p, Proposition q) {
    return conjunction(p, q);
}

auto operator||(Proposition p, Proposition q) {
    return disjunction(p, q);
}

auto operator==(Proposition p, Proposition q) {
    return equivalence(p, q);
}

// Output a Proposition
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, Proposition p) {
    match
        (*p,
         [&amp;](const Variable&amp; v) {
             os &lt;&lt; v.name;
         },
         [&amp;](const True&amp;) {
             os &lt;&lt; uch::True;
         },
         [&amp;](const False&amp;) {
             os &lt;&lt; uch::False;
         },
         [&amp;](const Negation&amp; p) {
             os &lt;&lt; uch::Negation &lt;&lt; &quot; &quot; &lt;&lt; p.child;
         },
         [&amp;](const Conjunction&amp; p) {
             os &lt;&lt; &quot;(&quot; &lt;&lt; p.left &lt;&lt; &quot; &quot; &lt;&lt; uch::Conjunction &lt;&lt; &quot; &quot; &lt;&lt; p.right &lt;&lt; &quot;)&quot;;
         },
         [&amp;](const Disjunction&amp; p) {
             os &lt;&lt; &quot;(&quot; &lt;&lt; p.left &lt;&lt; &quot; &quot; &lt;&lt; uch::Disjunction &lt;&lt; &quot; &quot; &lt;&lt; p.right &lt;&lt; &quot;)&quot;;
         },
         [&amp;](const Implies&amp; p) {
             os &lt;&lt; &quot;(&quot; &lt;&lt; p.left &lt;&lt; &quot; &quot; &lt;&lt; uch::Implies &lt;&lt; &quot; &quot; &lt;&lt; p.right &lt;&lt; &quot;)&quot;;
         },
         [&amp;](const Equivalence&amp; p) {
             os &lt;&lt; &quot;(&quot; &lt;&lt; p.left &lt;&lt; &quot; &quot; &lt;&lt; uch::Equivalence &lt;&lt; &quot; &quot; &lt;&lt; p.right &lt;&lt; &quot;)&quot;;
         },
         [&amp;](const auto&amp;) {
             os &lt;&lt; &quot;???&quot;;
         }
         );
    return os;
}

// Simplification
Proposition simplify_not(Proposition child) {
    return match
        (*child,
         [](const True&amp; f) { return pfalse(); },
         [](const False&amp; f) { return ptrue(); },
         [&amp;](const Negation&amp; f) { return f.child; },
         [&amp;](const auto&amp;) { return negation(child); }
         );
}

Proposition simplify_and(Proposition left, Proposition right) {
    if (std::holds_alternative&lt;False&gt;(*left) or std::holds_alternative&lt;False&gt;(*right))
        return pfalse();
    else if (std::holds_alternative&lt;True&gt;(*left) and std::holds_alternative&lt;True&gt;(*right))
        return ptrue();
    else
        return conjunction(left, right);
}

Proposition simplify_or(Proposition left, Proposition right) {
    if (std::holds_alternative&lt;False&gt;(*left) and std::holds_alternative&lt;False&gt;(*right))
        return pfalse();
    else if (std::holds_alternative&lt;True&gt;(*left) or std::holds_alternative&lt;True&gt;(*right))
        return ptrue();
    else
        return disjunction(left, right);
}

Proposition simplify(Proposition node) {
    return match
        (*node,
         [&amp;](const Negation&amp; f) {  return simplify_not(simplify(f.child)); },
         [&amp;](const Conjunction&amp; f) { return simplify_and(simplify(f.left), simplify(f.right)); },
         [&amp;](const Disjunction&amp; f) { return simplify_or(simplify(f.left), simplify(f.right)); },
         [&amp;](const auto&amp;) { return node; }
         );
}

huangapple
  • 本文由 发表于 2023年5月22日 08:21:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302425.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定