Tropical algebra overloading: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
No edit summary
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(12 intermediate revisions by 7 users not shown)
Line 1:
{{draft task}}
 
In algebra, a max tropical semiring (also called a max-plus algebra) is the semiring
Line 34:
Algol 68 allows operator overloading and even re-defining the built in operators (though the latter is probably frowned on).<br>
Either existing symbols or new symbols or "bold" (normally uppercase) words can be used. Unfortunately, (X) and (+) can't be used as operator symbols, so X is used for (X), + for (+) and ^ for exponentiaion. The standard + and ^ operators are redefined.<br>
<langsyntaxhighlight lang="algol68">BEGIN # tropical algebra operator overloading #
 
REAL minus inf = - max real;
Line 71:
check( 5 X ( 8 + 7 ), "5 (X) ( 8 (+) 7 ) = 5 (X) 8 (+) 5 (X) 7", 5 X 8 + 5 X 7 )
END
END</langsyntaxhighlight>
{{out}}
<pre>
Line 81:
5 ^ 7: 35.0
5 (X) ( 8 (+) 7 ) = 5 (X) 8 (+) 5 (X) 7 is TRUE
</pre>
 
 
=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
using System;
 
public class Program
{
public static void Main(string[] args)
{
var a = new Tropical(-2);
var b = new Tropical(-1);
var c = new Tropical(-0.5);
var d = new Tropical(-0.001);
var e = new Tropical(0);
var f = new Tropical(1.5);
var g = new Tropical(2);
var h = new Tropical(5);
var i = new Tropical(7);
var j = new Tropical(8);
var k = new Tropical(); // Represents -Inf
 
Console.WriteLine("2 x -2 = " + g.Multiply(a));
Console.WriteLine("-0.001 + -Inf = " + d.Add(k));
Console.WriteLine("0 x -Inf = " + e.Multiply(k));
Console.WriteLine("1.5 + -1 = " + f.Add(b));
Console.WriteLine("-0.5 x 0 = " + c.Multiply(e));
 
Console.WriteLine();
Console.WriteLine("5^7 = " + h.Power(7));
 
Console.WriteLine();
Console.WriteLine("5 * ( 8 + 7 ) = " + h.Multiply(j.Add(i)));
Console.WriteLine("5 * 8 + 5 * 7 = " + h.Multiply(j).Add(h.Multiply(i)));
}
}
 
public class Tropical
{
private double? number;
 
public Tropical(double number)
{
this.number = number;
}
 
public Tropical()
{
this.number = null; // Represents -Inf
}
 
public override string ToString()
{
return number.HasValue ? ((int)number.Value).ToString() : "-Inf";
}
 
public Tropical Add(Tropical other)
{
if (!number.HasValue) return other;
if (!other.number.HasValue) return this;
 
return number > other.number ? this : other;
}
 
public Tropical Multiply(Tropical other)
{
if (number.HasValue && other.number.HasValue)
{
return new Tropical(number.Value + other.number.Value);
}
 
return new Tropical();
}
 
public Tropical Power(int exponent)
{
if (exponent <= 0)
{
throw new ArgumentException("Power must be positive", nameof(exponent));
}
 
Tropical result = this;
for (int i = 1; i < exponent; i++)
{
result = result.Multiply(this);
}
 
return result;
}
}
</syntaxhighlight>
{{out}}
<pre>
2 x -2 = 0
-0.001 + -Inf = 0
0 x -Inf = -Inf
1.5 + -1 = 1
-0.5 x 0 = 0
 
5^7 = 35
 
5 * ( 8 + 7 ) = 13
5 * 8 + 5 * 7 = 13
 
</pre>
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <optional>
 
Line 207 ⟶ 313:
}
 
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 223 ⟶ 329:
=={{header|Factor}}==
{{works with|Factor|0.99 2021-06-02}}
<langsyntaxhighlight lang="factor">USING: io kernel math math.order present prettyprint sequences
typed ;
 
Line 244 ⟶ 350:
[ 5 8 ⊗ 5 7 ⊗ ⊕ ]
[ 8 7 ⊕ 5 ⊗ 5 8 ⊗ 5 7 ⊗ ⊕ = ]
} [ show ] each</langsyntaxhighlight>
{{out}}
<pre>
Line 261 ⟶ 367:
=={{header|FreeBASIC}}==
Using preprocessor macros.
<langsyntaxhighlight lang="freebasic">#define Inf 9223372036854775807
#define tropicalAdd(x,y) iif((x > y), (x), (y))
#define tropicalMul(x,y) (x + y)
Line 276 ⟶ 382:
Print "tropicalMul(5,tropicalAdd(8,7)) = tropicalAdd(tropicalMul(5,8),tropicalMul(5,7)) = "; _
CBool(tropicalMul(5,tropicalAdd(8,7)) = tropicalAdd(tropicalMul(5,8),tropicalMul(5,7)))
Sleep</langsyntaxhighlight>
 
 
Line 282 ⟶ 388:
{{trans|Wren}}
Go doesn't support operator overloading so we need to use functions instead.
<langsyntaxhighlight lang="go">package main
 
import (
Line 375 ⟶ 481:
fmt.Printf("%s ⊗ %s ⊕ %s ⊗ %s = %s\n", c, d, c, e, g)
fmt.Printf("%s ⊗ (%s ⊕ %s) == %s ⊗ %s ⊕ %s ⊗ %s is %t\n", c, d, e, c, d, c, e, f.eq(g))
}</langsyntaxhighlight>
 
{{out}}
Line 392 ⟶ 498:
=={{header|Haskell}}==
Looks like the Haskell pretty printer thinks the single quote in 'Maxima begins a character constant.
<langsyntaxhighlight lang="haskell">{-# LANGUAGE DataKinds, DerivingVia, FlexibleInstances, StandaloneDeriving #-}
 
import Prelude hiding ((^))
Line 487 ⟶ 593:
 
opError :: String -> a
opError op = error $ op ++ " is not defined on a max-plus semiring"</langsyntaxhighlight>
 
{{out}}
Line 500 ⟶ 606:
Expecting 5 ⊗ 8 ⊕ 5 ⊗ 7 == 13. Got 13.0 ✔
</pre>
 
=={{header|Java}}==
<syntaxhighlight lang="java">
import java.util.Optional;
 
public final class TropicalAlgebra {
 
public static void main(String[] aArgs) {
final Tropical a = new Tropical(-2);
final Tropical b = new Tropical(-1);
final Tropical c = new Tropical(-0.5);
final Tropical d = new Tropical(-0.001);
final Tropical e = new Tropical(0);
final Tropical f = new Tropical(1.5);
final Tropical g = new Tropical(2);
final Tropical h = new Tropical(5);
final Tropical i = new Tropical(7);
final Tropical j = new Tropical(8);
final Tropical k = new Tropical();
System.out.println("2 x -2 = " + g.multiply(a));
System.out.println("-0.001 + -Inf = " + d.add(k));
System.out.println("0 x -Inf = " + e.multiply(k));
System.out.println("1.5 + -1 = " + f.add(b));
System.out.println("-0.5 x 0 = " + c.multiply(e));
System.out.println();
System.out.println("5^7 = " + h.power(7));
System.out.println();
System.out.println("5 * ( 8 + 7 ) = " + h.multiply(j.add(i)));
System.out.println("5 * 8 + 5 * 7 = " + h.multiply(j).add(h.multiply(i)));
}
 
}
 
final class Tropical {
public Tropical(Number aNumber) {
if ( aNumber == null ) {
throw new IllegalArgumentException("Number cannot be null");
}
optional = Optional.of(aNumber);
}
public Tropical() {
optional = Optional.empty();
}
@Override
public String toString() {
if ( optional.isEmpty() ) {
return "-Inf";
}
String value = String.valueOf(optional.get());
final int index = value.indexOf(".");
if ( index >= 0 ) {
value = value.substring(0, index);
}
return value;
}
public Tropical add(Tropical aOther) {
if ( aOther.optional.isEmpty() ) {
return this;
}
if ( optional.isEmpty() ) {
return aOther;
}
if ( optional.get().doubleValue() > aOther.optional.get().doubleValue() ) {
return this;
}
return aOther;
}
public Tropical multiply(Tropical aOther) {
if ( optional.isPresent() && aOther.optional.isPresent() ) {
double result = optional.get().doubleValue() + aOther.optional.get().doubleValue();
return new Tropical(result);
}
return new Tropical();
}
public Tropical power(int aExponent) {
if ( aExponent <= 0 ) {
throw new IllegalArgumentException("Power must be positive");
}
Tropical result = this;;
for ( int i = 1; i < aExponent; i++ ) {
result = result.multiply(this);
}
return result;
}
private Optional<Number> optional;
}
</syntaxhighlight>
{{ out }}
<pre>
2 x -2 = 0
-0.001 + -Inf = -0
0 x -Inf = -Inf
1.5 + -1 = 1
-0.5 x 0 = -0
 
5^7 = 35
 
5 * ( 8 + 7 ) = 13
5 * 8 + 5 * 7 = 13
</pre>
 
=={{header|jq}}==
{{works with|jq}}
 
'''Also work with gojq''' subject to the qualifications described below.
 
In this entry, jq's support for "::" in definitions is used. This
feature is not supported by gojq, so to adapt the following for gojq,
one could either modify the names, or place the definitions in a
module named `Tropical` and delete the "Tropical::" prefix within the
module itself.
 
Since the jq values for plus and minus infinity are `infinite` and
`-infinite` respectively, no special constructor for Tropical
numbers is needed.
 
Note that in the following, no checks for the validity of inputs are
included.
<syntaxhighlight lang=jq>
# ⊕ operator
def Tropical::add($other):
[., $other] | max;
 
# ⊗ operator
def Tropical::mul($other):
. + $other;
 
# Tropical exponentiation
def Tropical::exp($e):
if ($e|type) == "number" and ($e | . == floor)
then if ($e == 1) then .
else . as $in
| reduce range (2;1+$e) as $i (.; Tropical::mul($in))
end
else "Tropical::exp(\($e)): argument must be a positive integer." | error
end ;
 
# pretty print a number as a Tropical number
def pp:
if isinfinite then if . > 0 then "infinity" else "-infinity" end
else .
end;
def data: [
[2, -2, "⊗"],
[-0.001, -infinite, "⊕"],
[0, -infinite, "⊗"],
[1.5, -1, "⊕"],
[-0.5, 0, "⊗"]
];
 
def task1:
data[] as [$a, $b, $op]
| if $op == "⊕"
then "\($a|pp) ⊕ \($b|pp) = \($a | Tropical::add($b) | pp)"
else
"\($a|pp) ⊗ \($b|pp) = \($a | Tropical::mul($b) | pp)"
end;
 
def task2:
5 as $c
| "\($c|pp) ^ 7 = \($c | Tropical::exp(7) | pp)";
def task3:
5 as $c
| 8 as $d
| 7 as $e
| ($c | Tropical::mul($d) | Tropical::add($e)) as $f
| ($c | Tropical::mul($d) | Tropical::add( $c | Tropical::mul($e))) as $g
| "\($c) ⊗ (\($d) ⊕ \($e)) = \($f | pp)",
"\($c) ⊗ \($d) ⊕ \($c) ⊗ \($e) = \($g | pp)",
"\($c) ⊗ (\($d) ⊕ \($e)) == \($c) ⊗ \($d) ⊕ \($c) ⊗ \($e) is \($f == $g)" ;
 
task1, task2, task3
</syntaxhighlight>
{{output}}
See e.g. [[#Wren|Wren]].
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">⊕(x, y) = max(x, y)
⊗(x, y) = x + y
↑(x, y) = (@assert round(y) == y && y > 0; x * y)
Line 515 ⟶ 817:
@show 5 ⊗ 8 ⊕ 5 ⊗ 7
@show 5 ⊗ (8 ⊕ 7) == 5 ⊗ 8 ⊕ 5 ⊗ 7
</langsyntaxhighlight>{{out}}
<pre>
2 ⊗ -2 = 0
Line 533 ⟶ 835:
We also defined the -Inf value as a constant, MinusInfinity.
 
<langsyntaxhighlight Nimlang="nim">import strformat
 
type MaxTropical = distinct float
Line 577 ⟶ 879:
echo &"5 ⊗ (8 ⊕ 7) = {x}"
echo &"5 ⊗ 8 ⊕ 5 ⊗ 7 = {y}"
echo &"So 5 ⊗ (8 ⊕ 7) equals 5 ⊗ 8 ⊕ 5 ⊗ 7 is {x == y}."</langsyntaxhighlight>
 
{{out}}
Line 593 ⟶ 895:
=={{header|Phix}}==
Phix does not support operator overloading. I trust max is self-evident, sq_add and sq_mul are existing wrappers to the + and * operators, admittedly with extra (sequence) functionality we don't really need here, but they'll do just fine.
<!--<langsyntaxhighlight Phixlang="phix">(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #7060A8;">requires</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"1.0.1"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (minor/backportable bugfix rqd to handling of -inf in printf[1])</span>
Line 619 ⟶ 921:
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"tropicalMul(5,tropicalAdd(8,7)) == tropicalAdd(tropicalMul(5,8),tropicalMul(5,7)) = %t\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">tropicalMul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tropicalAdd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">))</span> <span style="color: #0000FF;">==</span> <span style="color: #000000;">tropicalAdd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tropicalMul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">),</span><span style="color: #000000;">tropicalMul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">))})</span>
<!--</langsyntaxhighlight>-->
<small>[1]This task exposed a couple of "and o!=inf" that needed to become "and o!=inf and o!=-inf" in builtins\VM\pprintfN.e - thanks!</small>
{{out}}
Line 635 ⟶ 937:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from numpy import Inf
 
class MaxTropical:
Line 687 ⟶ 989:
print("5 * (8 + 7) == 5 * 8 + 5 * 7", j * (l + k) == j * l + j * k)
 
</langsyntaxhighlight>{{out}}
<pre>
2 * -2 == 0
Line 702 ⟶ 1,004:
=={{header|R}}==
R's overloaded operators, denoted by %_%, have different precedence order than + and *, so parentheses are needed for the distributive example.
<langsyntaxhighlight lang="r">"%+%"<- function(x, y) max(x, y)
 
"%*%" <- function(x, y) x + y
Line 720 ⟶ 1,022:
cat("5 %*% 8 %+% 5 %*% 7 ==", (5 %*% 8) %+% (5 %*% 7), "\n")
cat("5 %*% 8 %+% 5 %*% 7 == 5 %*% (8 %+% 7))", 5 %*% (8 %+% 7) == (5 %*% 8) %+% (5 %*% 7), "\n")
</langsyntaxhighlight>{{out}}
<pre>
2 %*% -2 == 0
Line 736 ⟶ 1,038:
No need to overload, define our own operators with whatever precedence level we want. Here we're setting precedence equivalent to existing operators.
 
<syntaxhighlight lang="raku" perl6line>sub infix:<⊕> (Real $a, Real $b) is equiv(&[+]) { $a max $b }
sub infix:<⊗> (Real $a, Real $b) is equiv(&[×]) { $a + $b }
sub infix:<↑> (Real $a, Int $b where * ≥ 0) is equiv(&[**]) { [⊗] $a xx $b }
Line 749 ⟶ 1,051:
is-deeply( 5 ↑ 7, 35, '5 ↑ 7 == 35' );
is-deeply( 5 ⊗ (8 ⊕ 7), 5 ⊗ 8 ⊕ 5 ⊗ 7, '5 ⊗ (8 ⊕ 7) == 5 ⊗ 8 ⊕ 5 ⊗ 7');
is-deeply( 5 ↑ 7 ⊕ 6 ↑ 6, 36, '5 ↑ 7 ⊕ 6 ↑ 6 == 36');</langsyntaxhighlight>
{{out}}
<pre>ok 1 - 2 ⊗ -2 == 0
Line 762 ⟶ 1,064:
=={{header|REXX}}==
'''REXX''' &nbsp; doesn't support operator overloading, &nbsp; so functions are needed to be used instead.
<langsyntaxhighlight lang="rexx">/*REXX pgm demonstrates max tropical semi─ring with overloading: topAdd, topMul, topExp.*/
call negInf; @x= '(x)'; @a= '(+)'; @h= '(^)'; @e= 'expression'; @c= 'comparison'
numeric digits 1000 /*be able to handle negative infinity. */
Line 800 ⟶ 1,102:
/*──────────────────────────────────────────────────────────────────────────────────────*/
isRing: procedure; parse arg a,b; if ABnInf() then return negInf /*return -∞ */
if isNum(a) | a==negInf() then return a; call notNum a /*show error.*/</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the internal default input:}}
<pre>
Line 815 ⟶ 1,117:
</pre>
 
=={{header|VlangRPL}}==
RPL does not support operator overloading so we need to use functions instead. As all stack-driven languages, RPL requires the user to deal with operator precedence.
MAXR EVAL '<span style="color:green>Inf</span>' STO
≪ 1 3 '''START''' ROT EVAL '''NEXT'''
'''IF''' DUP ABS <span style="color:green>Inf</span> == '''THEN''' SIGN '<span style="color:green>Inf</span>' * '''END'''
≫ ‘<span style="color:blue>TropOp</span>’ STO
≪ ≪ MAX ≫ <span style="color:blue>TropOp</span> ≫ ‘<span style="color:blue>TPLUS</span>’ STO
≪ ≪ + ≫ <span style="color:blue>TropOp</span> ≫ ‘<span style="color:blue>TMULT</span>’ STO
≪ ≪ * ≫ <span style="color:blue>TropOp</span> ≫ ‘<span style="color:blue>TPOWR</span>’ STO
 
2 -2 <span style="color:blue>TMULT</span>
-0.001 -<span style="color:green>Inf</span> <span style="color:blue>TPLUS</span>
0 -<span style="color:green>Inf</span> <span style="color:blue>TMULT</span>
1.5 -1 <span style="color:blue>TPLUS</span>
0.5 0 <span style="color:blue>TMULT</span>
5 7 <span style="color:blue>TPOWR</span>
8 7 <span style="color:blue>TPLUS</span> 5 <span style="color:blue>TMULT</span>
5 8 <span style="color:blue>TMULT</span> 5 7 <span style="color:blue>TMULT</span> <span style="color:blue>TPLUS</span>
 
{{out}}
<pre>
8: 0
7: -0.001
6: '-Inf'
5: 1.5
4: -0.5
3: 35
2: 13
1: 13
</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
Vlang doesn't support operator overloading so we need to use functions instead.
<syntaxhighlight lang="v (vlang)">import math
const (
Line 909 ⟶ 1,246:
println("$c ⊗ $d ⊕ $c ⊗ $e = $g")
println("$c ⊗ ($d ⊕ $e) == $c ⊗ $d ⊕ $c ⊗ $e is ${f.eq(g)}")
}</langsyntaxhighlight>
 
{{out}}
Line 925 ⟶ 1,262:
 
=={{header|Wren}}==
<langsyntaxhighlight ecmascriptlang="wren">var MinusInf = -1/0
 
class MaxTropical {
Line 998 ⟶ 1,335:
System.print("%(c) ⊗ (%(d) ⊕ %(e)) = %(f)")
System.print("%(c) ⊗ %(d) ⊕ %(c) ⊗ %(e) = %(g)")
System.print("%(c) ⊗ (%(d) ⊕ %(e)) == %(c) ⊗ %(d) ⊕ %(c) ⊗ %(e) is %(f == g)")</langsyntaxhighlight>
 
{{out}}
9,477

edits