Skip to content

Commit

Permalink
feat: Add Tropical (#202)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikuroXina committed May 11, 2024
1 parent b69b141 commit 5eb7ae3
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 0 deletions.
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export * as String from "./src/string.ts";
export * as Tagged from "./src/tagged.ts";
export * as These from "./src/these.ts";
export * as Trans from "./src/trans.ts";
export * as Tropical from "./src/tropical.ts";
export * as Tuple from "./src/tuple.ts";
export * as TupleN from "./src/tuple-n.ts";
export * as TypeClass from "./src/type-class.ts";
Expand Down
80 changes: 80 additions & 0 deletions src/tropical.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* This module provides a structure that denotes tropical semi-ring.
*
* Additive and multiplication of `Tropical` variable x and y is defined as:
*
* - `add(x, y)` := `Math.min(x, y)`,
* - `mul(x, y)` := `x + y`.
*
* This module exports `semiRing` which is about this mathematical structure.
*
* @packageDocumentation
* @module
*/

import { none, type Option, some } from "./option.ts";
import { abelSymbol } from "./type-class/abelian-group.ts";
import type { AbelianMonoid } from "./type-class/abelian-monoid.ts";
import type { Monoid } from "./type-class/monoid.ts";
import { semiGroupSymbol } from "./type-class/semi-group.ts";
import type { SemiRing } from "./type-class/semi-ring.ts";

declare const tropicalNominal: unique symbol;
/**
* A tropical semi-ring data which consists of finite numbers and positive infinity.
*/
export type Tropical = number & { [tropicalNominal]: never };

/**
* Transforms a number into a `Tropical`.
*
* @param num - Source integer.
* @returns The new number of `Tropical`.
*
* # Throws
*
* It throws an error only if `num` is negative infinity or NaN.
*/
export const fromNumber = (num: number): Tropical => {
if (Number.NEGATIVE_INFINITY < num) {
return num as Tropical;
}
throw new Error("tropical num must be finite or positive infinity");
};

/**
* Checks and transforms a number into a `Tropical`.
*
* @param num - Source integer.
* @returns The new number of `Tropical`, or none if failed.
*/
export const fromNumberChecked = (num: number): Option<Tropical> => {
if (Number.NEGATIVE_INFINITY < num) {
return some(num as Tropical);
}
return none();
};

/**
* Additive about `Math.min` on `Tropical`.
*/
export const additive: AbelianMonoid<Tropical> = {
identity: Number.POSITIVE_INFINITY as Tropical,
combine: (l, r) => Math.min(l, r) as Tropical,
[abelSymbol]: true,
[semiGroupSymbol]: true,
};

/**
* Multiplication about `+` on `Tropical`.
*/
export const multiplication: Monoid<Tropical> = {
identity: 0 as Tropical,
combine: (l, r) => (l + r) as Tropical,
[semiGroupSymbol]: true,
};

/**
* Semi-ring about `Math.min` as additive and `+` as multiplication on `Tropical`.
*/
export const semiRing: SemiRing<Tropical> = { additive, multiplication };
2 changes: 2 additions & 0 deletions src/type-class.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * as AbelianGroup from "./type-class/abelian-group.ts";
export * as AbelianMonoid from "./type-class/abelian-monoid.ts";
export * as Applicative from "./type-class/applicative.ts";
export * as Apply from "./type-class/apply.ts";
export * as Arrow from "./type-class/arrow.ts";
Expand Down Expand Up @@ -41,6 +42,7 @@ export * as Ring from "./type-class/ring.ts";
export * as SemiGroup from "./type-class/semi-group.ts";
export * as SemiGroupal from "./type-class/semi-groupal.ts";
export * as SemiGroupoid from "./type-class/semi-groupoid.ts";
export * as SemiRing from "./type-class/semi-ring.ts";
export * as Settable from "./type-class/settable.ts";
export * as Strong from "./type-class/strong.ts";
export * as Symmetric from "./type-class/symmetric.ts";
Expand Down
6 changes: 6 additions & 0 deletions src/type-class/abelian-monoid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { abelSymbol } from "./abelian-group.ts";
import type { Monoid } from "./monoid.ts";

export interface AbelianMonoid<T> extends Monoid<T> {
[abelSymbol]: true;
}
16 changes: 16 additions & 0 deletions src/type-class/semi-ring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { AbelianMonoid } from "./abelian-monoid.ts";
import type { Monoid } from "./monoid.ts";

/**
* A `SemiRing` instance for `T` must satisfy these laws:
*
* - Additive is an abelian monoid. The identity of `additive` is called `zero`.
* - Multiplication is a monoid. The identity of `multiplication` is called `one`.
* - On multiplication, any element `x` is left and right annihilated by `zero`:
* - `multiplication.combine(zero, x)` = `zero`,
* - `multiplication.combine(x, zero)` = `zero`.
*/
export interface SemiRing<T> {
additive: AbelianMonoid<T>;
multiplication: Monoid<T>;
}

0 comments on commit 5eb7ae3

Please sign in to comment.