Tropical algebra overloading: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
(Tropical algebra overloading en FreeBASIC)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(14 intermediate revisions by 9 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 389 ⟶ 495:
5 ⊗ (8 ⊕ 7) == 5 ⊗ 8 ⊕ 5 ⊗ 7 is true
</pre>
 
=={{header|Haskell}}==
Looks like the Haskell pretty printer thinks the single quote in 'Maxima begins a character constant.
<syntaxhighlight lang="haskell">{-# LANGUAGE DataKinds, DerivingVia, FlexibleInstances, StandaloneDeriving #-}
 
import Prelude hiding ((^))
import Data.Monoid (Sum(Sum))
import Data.Number.CReal (CReal)
import Data.Semiring (Semiring, (^), plus, times)
import Data.Semiring.Tropical (Tropical(..), Extrema(Maxima))
 
-- Create our max-plus semiring over the constructive reals (CReal), using the
-- Tropical type from the semirings package. (We'll put all the boilerplate
-- code after the main function.)
--
-- 'Maxima indicates that our semiring is a max-plus semiring, where the plus
-- function is maximum, the times function is addition, and the Infinity
-- constructor is treated as -∞.
 
newtype MaxPlus = MaxPlus (Tropical 'Maxima CReal)
 
-- Symbolic aliases to satisfy the problem requirements.
 
(⊕), (⊗) :: MaxPlus -> MaxPlus -> MaxPlus
(⊕) = plus
(⊗) = times
 
infixl 6 ⊕
infixl 7 ⊗
 
(↑) :: Integral a => MaxPlus -> a -> MaxPlus
(↑) = (^)
 
infixr 8 ↑
 
main :: IO ()
main = do
-- Description Equation Expected Value
test "2 ⊗ (-2) == 0" (2 ⊗ (-2)) 0
test "-0.001 ⊕ -Inf == -0.001" (-0.001 ⊕ MaxPlus Infinity) (-0.001)
test "0 ⊗ -Inf == -Inf" (0 ⊗ MaxPlus Infinity) (MaxPlus Infinity)
test "1.5 ⊕ -1 == 1.5" (1.5 ⊕ (-1)) 1.5
test "-0.5 ⊗ 0 == -0.5" ((-0.5) ⊗ 0) (-0.5)
test "5 ↑ 7 == 35" (5 ↑ 7) 35
test "5 ⊗ (8 ⊕ 7) == 13" (5 ⊗ (8 ⊕ 7)) 13
test "5 ⊗ 8 ⊕ 5 ⊗ 7 == 13" (5 ⊗ 8 ⊕ 5 ⊗ 7) 13
 
--------------------------------------------------------------------------------
 
-- Boilerplate, utility functions, etc.
 
-- Bootstrap our way to having MaxPlus be a Semiring instance. Also, derive
-- Eq and Ord instances.
deriving via (Sum CReal) instance Semigroup CReal
deriving via (Sum CReal) instance Monoid CReal
deriving via Tropical 'Maxima CReal instance Semiring MaxPlus
deriving via Tropical 'Maxima CReal instance Eq MaxPlus
deriving via Tropical 'Maxima CReal instance Ord MaxPlus
 
-- Create a Num instance for MaxPlus mostly so that we can use fromInteger and
-- negate. This lets us treat the numeric literal -2, for example, as a value
-- in our semiring.
instance Num MaxPlus where
(+) = plus
(*) = times
abs = opError "absolute value"
signum (MaxPlus Infinity) = -1
signum x = wrap . signum . unwrap $ x
fromInteger = wrap . fromInteger
negate (MaxPlus Infinity) = opError "negation of -Inf"
negate x = wrap . negate . unwrap $ x
 
-- Similar to Num, this will let us treat numeric literals, like 0.001, as
-- MaxPlus values.
instance Fractional MaxPlus where
fromRational = wrap . fromRational
recip _ = opError "reciprocal"
 
instance Show MaxPlus where
show (MaxPlus Infinity) = "-Inf"
show x = show . unwrap $ x
 
-- Test two expressions for equality.
test :: String -> MaxPlus -> MaxPlus -> IO ()
test s actual expected = do
putStr $ "Expecting " ++ s ++ ". Got " ++ show actual ++ " "
putStrLn $ if actual == expected then "✔" else "✘"
 
-- Utility functions.
 
wrap :: CReal -> MaxPlus
wrap = MaxPlus . Tropical
 
unwrap :: MaxPlus -> CReal
unwrap (MaxPlus (Tropical x)) = x
unwrap (MaxPlus Infinity) = error "can't convert -Inf to a CReal"
 
opError :: String -> a
opError op = error $ op ++ " is not defined on a max-plus semiring"</syntaxhighlight>
 
{{out}}
<pre>
Expecting 2 ⊗ (-2) == 0. Got 0.0 ✔
Expecting -0.001 ⊕ -Inf == -0.001. Got -0.001 ✔
Expecting 0 ⊗ -Inf == -Inf. Got -Inf ✔
Expecting 1.5 ⊕ -1 == 1.5. Got 1.5 ✔
Expecting -0.5 ⊗ 0 == -0.5. Got -0.5 ✔
Expecting 5 ↑ 7 == 35. Got 35.0 ✔
Expecting 5 ⊗ (8 ⊕ 7) == 13. Got 13.0 ✔
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 404 ⟶ 817:
@show 5 ⊗ 8 ⊕ 5 ⊗ 7
@show 5 ⊗ (8 ⊕ 7) == 5 ⊗ 8 ⊕ 5 ⊗ 7
</langsyntaxhighlight>{{out}}
<pre>
2 ⊗ -2 = 0
Line 422 ⟶ 835:
We also defined the -Inf value as a constant, MinusInfinity.
 
<langsyntaxhighlight Nimlang="nim">import strformat
 
type MaxTropical = distinct float
Line 466 ⟶ 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 482 ⟶ 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 508 ⟶ 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 524 ⟶ 937:
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from numpy import Inf
 
class MaxTropical:
Line 576 ⟶ 989:
print("5 * (8 + 7) == 5 * 8 + 5 * 7", j * (l + k) == j * l + j * k)
 
</langsyntaxhighlight>{{out}}
<pre>
2 * -2 == 0
Line 591 ⟶ 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 609 ⟶ 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 625 ⟶ 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 638 ⟶ 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 651 ⟶ 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 689 ⟶ 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 702 ⟶ 1,115:
max tropical comparison of 5 (x) with (+)(8,7) compared to
(x)(5,8) with (+) (x)(5,7) ───► true
</pre>
 
=={{header|RPL}}==
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 (
minus_inf = math.inf(-1)
)
struct MaxTropical { r f64 }
fn new_max_tropical(r f64) ?MaxTropical {
if math.is_inf(r, 1) || math.is_nan(r) {
return error("Argument must be a real number or negative infinity.")
}
return MaxTropical{r}
}
fn (t MaxTropical) eq(other MaxTropical) bool {
return t.r == other.r
}
// equivalent to ⊕ operator
fn (t MaxTropical) add(other MaxTropical) ?MaxTropical {
if t.r == minus_inf {
return other
}
if other.r == minus_inf {
return t
}
return new_max_tropical(math.max(t.r, other.r))
}
// equivalent to ⊗ operator
fn (t MaxTropical) mul(other MaxTropical) ?MaxTropical {
if t.r == 0 {
return other
}
if other.r == 0 {
return t
}
return new_max_tropical(t.r + other.r)
}
// exponentiation fntion
fn (t MaxTropical) pow(e int) ?MaxTropical {
if e < 1 {
return error("Exponent must be a positive integer.")
}
if e == 1 {
return t
}
mut p := t
for i := 2; i <= e; i++ {
p = p.mul(t)?
}
return p
}
fn (t MaxTropical) str() string {
return '${t.r}'
}
fn main() {
// 0 denotes ⊕ and 1 denotes ⊗
data := [
[2.0, -2, 1],
[-0.001, minus_inf, 0],
[0.0, minus_inf, 1],
[1.5, -1, 0],
[-0.5, 0, 1],
]
for d in data {
a := new_max_tropical(d[0])?
b := new_max_tropical(d[1])?
c := a.add(b)?
m := a.mul(b)?
if d[2] == 0 {
println("$a ⊕ $b = $c")
} else {
println("$a ⊗ $b = $m")
}
}
c := new_max_tropical(5)?
println("$c ^ 7 = ${c.pow(7)}")
d := new_max_tropical(8)?
e := new_max_tropical(7)?
f := c.mul(d.add(e)?)?
g := c.mul(d)?.add(c.mul(e)?)?
println("$c ⊗ ($d ⊕ $e) = $f")
println("$c ⊗ $d ⊕ $c ⊗ $e = $g")
println("$c ⊗ ($d ⊕ $e) == $c ⊗ $d ⊕ $c ⊗ $e is ${f.eq(g)}")
}</syntaxhighlight>
 
{{out}}
<pre>
2 ⊗ -2 = 0
-0.001 ⊕ -inf = -0.001
0 ⊗ -inf = -inf
1.5 ⊕ -1 = 1.5
-0.5 ⊗ 0 = -0.5
5 ^ 7 = Option(35)
5 ⊗ (8 ⊕ 7) = 13
5 ⊗ 8 ⊕ 5 ⊗ 7 = 13
5 ⊗ (8 ⊕ 7) == 5 ⊗ 8 ⊕ 5 ⊗ 7 is true
</pre>
 
=={{header|Wren}}==
<langsyntaxhighlight ecmascriptlang="wren">var MinusInf = -1/0
 
class MaxTropical {
Line 778 ⟶ 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,482

edits