package element

import (
    "fmt"
    "math"
)

type Matrix struct {
    ele    []float64
    stride int
}

func MatrixFromRows(rows [][]float64) Matrix {
    if len(rows) == 0 {
        return Matrix{nil, 0}
    }
    m := Matrix{make([]float64, len(rows)*len(rows[0])), len(rows[0])}
    for rx, row := range rows {
        copy(m.ele[rx*m.stride:(rx+1)*m.stride], row)
    }
    return m
}

func like(m Matrix) Matrix {
    return Matrix{make([]float64, len(m.ele)), m.stride}
}

func (m Matrix) String() string {
    s := ""
    for e := 0; e < len(m.ele); e += m.stride {
        s += fmt.Sprintf("%6.3f \n", m.ele[e:e+m.stride])
    }
    return s
}

type binaryFunc64 func(float64, float64) float64

func elementWiseMM(m1, m2 Matrix, f binaryFunc64) Matrix {
    z := like(m1)
    for i, m1e := range m1.ele {
        z.ele[i] = f(m1e, m2.ele[i])
    }
    return z
}

func elementWiseMS(m Matrix, s float64, f binaryFunc64) Matrix {
    z := like(m)
    for i, e := range m.ele {
        z.ele[i] = f(e, s)
    }
    return z
}

func add(a, b float64) float64 { return a + b }
func sub(a, b float64) float64 { return a - b }
func mul(a, b float64) float64 { return a * b }
func div(a, b float64) float64 { return a / b }
func exp(a, b float64) float64 { return math.Pow(a, b) }

func AddMatrix(m1, m2 Matrix) Matrix { return elementWiseMM(m1, m2, add) }
func SubMatrix(m1, m2 Matrix) Matrix { return elementWiseMM(m1, m2, sub) }
func MulMatrix(m1, m2 Matrix) Matrix { return elementWiseMM(m1, m2, mul) }
func DivMatrix(m1, m2 Matrix) Matrix { return elementWiseMM(m1, m2, div) }
func ExpMatrix(m1, m2 Matrix) Matrix { return elementWiseMM(m1, m2, exp) }

func AddScalar(m Matrix, s float64) Matrix { return elementWiseMS(m, s, add) }
func SubScalar(m Matrix, s float64) Matrix { return elementWiseMS(m, s, sub) }
func MulScalar(m Matrix, s float64) Matrix { return elementWiseMS(m, s, mul) }
func DivScalar(m Matrix, s float64) Matrix { return elementWiseMS(m, s, div) }
func ExpScalar(m Matrix, s float64) Matrix { return elementWiseMS(m, s, exp) }


class NaiveMatrix {

    List<List<Number>> contents = []

    NaiveMatrix(Iterable<Iterable<Number>> elements) {
        contents.addAll(elements.collect{ row -> row.collect{ cell -> cell } })
        assertWellFormed()
    }

    void assertWellFormed() {
        assert contents != null
        assert contents.size() > 0
        def nCols = contents[0].size()
        assert nCols > 0
        assert contents.every { it != null && it.size() == nCols }
    }

    Map getOrder() { [r: contents.size() , c: contents[0].size()] }

    void assertConformable(NaiveMatrix that) { assert this.order == that.order }

    NaiveMatrix unaryOp(Closure op) {
        new NaiveMatrix(contents.collect{ row -> row.collect{ cell -> op(cell) } } )
    }
    NaiveMatrix binaryOp(NaiveMatrix m, Closure op) {
        assertConformable(m)
        new NaiveMatrix(
            (0..<(this.order.r)).collect{ i ->
                (0..<(this.order.c)).collect{ j -> op(this.contents[i][j],m.contents[i][j]) }
            }
        )
    }
    NaiveMatrix binaryOp(Number n, Closure op) {
        assert n != null
        new NaiveMatrix(contents.collect{ row -> row.collect{ cell -> op(cell,n) } } )
    }

    def plus = this.&binaryOp.rcurry { a, b -> a+b }

    def minus = this.&binaryOp.rcurry { a, b -> a-b }

    def multiply = this.&binaryOp.rcurry { a, b -> a*b }

    def div = this.&binaryOp.rcurry { a, b -> a/b }

    def mod = this.&binaryOp.rcurry { a, b -> a%b }

    def power = this.&binaryOp.rcurry { a, b -> a**b }

    def negative = this.&unaryOp.curry { - it }

    def recip = this.&unaryOp.curry { 1/it }

    String toString() {
        contents.toString()
    }

    boolean equals(Object other) {
        if (other == null || ! other instanceof NaiveMatrix) return false
        def that = other as NaiveMatrix
        this.contents == that.contents
    }

    int hashCode() {
        contents.hashCode()
    }
}


{-# OPTIONS_GHC -fno-warn-duplicate-constraints #-}
{-# LANGUAGE RankNTypes #-}

import Data.Array (Array, Ix)
import Data.Array.Base

-- | Element-wise combine the values of two arrays 'a' and 'b' with 'f'.
-- 'a' and 'b' must have the same bounds.
zipWithA :: (IArray arr a, IArray arr b, IArray arr c, Ix i) =>
            (a -> b -> c) -> arr i a -> arr i b -> arr i c
zipWithA f a b =
  case bounds a of
    ba ->
      if ba /= bounds b
      then error "elemwise: bounds mismatch"
      else
        let n = numElements a
        in unsafeArray ba [ (i, f (unsafeAt a i) (unsafeAt b i))
                          | i <- [0 .. n - 1]]

-- Convenient aliases for matrix-matrix element-wise operations.
type ElemOp a b c = (IArray arr a, IArray arr b, IArray arr c, Ix i) =>
                    arr i a -> arr i b -> arr i c
type ElemOp1 a = ElemOp a a a

infixl 6 +:, -:
infixl 7 *:, /:, `divE`

(+:), (-:), (*:) :: (Num a) => ElemOp1 a
(+:) = zipWithA (+)
(-:) = zipWithA (-)
(*:) = zipWithA (*)

divE :: (Integral a) => ElemOp1 a
divE = zipWithA div

(/:) :: (Fractional a) => ElemOp1 a
(/:) = zipWithA (/)

infixr 8 ^:, **:, ^^:

(^:) :: (Num a, Integral b) => ElemOp a b a
(^:) = zipWithA (^)

(**:) :: (Floating a) => ElemOp1 a
(**:) = zipWithA (**)

(^^:) :: (Fractional a, Integral b) => ElemOp a b a
(^^:) = zipWithA (^^)

-- Convenient aliases for matrix-scalar element-wise operations.
type ScalarOp a b c = (IArray arr a, IArray arr c, Ix i) =>
                      arr i a -> b -> arr i c
type ScalarOp1 a = ScalarOp a a a

samap :: (IArray arr a, IArray arr c, Ix i) =>
         (a -> b -> c) -> arr i a -> b -> arr i c
samap f a s = amap (`f` s) a

infixl 6 +., -.
infixl 7 *., /., `divS`

(+.), (-.), (*.) :: (Num a) => ScalarOp1 a
(+.) = samap (+)
(-.) = samap (-)
(*.) = samap (*)

divS :: (Integral a) => ScalarOp1 a
divS = samap div

(/.) :: (Fractional a) => ScalarOp1 a
(/.) = samap (/)

infixr 8 ^., **., ^^.

(^.) :: (Num a, Integral b) => ScalarOp a b a
(^.) = samap (^)

(**.) :: (Floating a) => ScalarOp1 a
(**.) = samap (**)

(^^.) :: (Fractional a, Integral b) => ScalarOp a b a
(^^.) = samap (^^)

main :: IO ()
main = do
  let m1, m2 :: (forall a. (Enum a, Num a) => Array (Int, Int) a)
      m1 = listArray ((0, 0), (2, 3)) [1..]
      m2 = listArray ((0, 0), (2, 3)) [10..]
      s :: (forall a. Num a => a)
      s = 99
  putStrLn "m1"
  print m1
  putStrLn "m2"
  print m2
  putStrLn "s"
  print s
  putStrLn "m1 + m2"
  print $ m1 +: m2
  putStrLn "m1 - m2"
  print $ m1 -: m2
  putStrLn "m1 * m2"
  print $ m1 *: m2
  putStrLn "m1 `div` m2"
  print $ m1 `divE` m2
  putStrLn "m1 / m2"
  print $ m1 /: m2
  putStrLn "m1 ^ m2"
  print $ m1 ^: m2
  putStrLn "m1 ** m2"
  print $ m1 **: m2
  putStrLn "m1 ^^ m2"
  print $ m1 ^^: m2
  putStrLn "m1 + s"
  print $ m1 +. s
  putStrLn "m1 - s"
  print $ m1 -. s
  putStrLn "m1 * s"
  print $ m1 *. s
  putStrLn "m1 `div` s"
  print $ m1 `divS` s
  putStrLn "m1 / s"
  print $ m1 /. s
  putStrLn "m1 ^ s"
  print $ m1 ^. s
  putStrLn "m1 ** s"
  print $ m1 **. s
  putStrLn "m1 ^^ s"
  print $ m1 ^^. s


procedure main()
   a := [[1,2,3],[4,5,6],[7,8,9]]
   b := [[9,8,7],[6,5,4],[3,2,1]]
   showMat("  a: ",a)
   showMat("  b: ",b)
   showMat("a+b: ",mmop("+",a,b))
   showMat("a-b: ",mmop("-",a,b))
   showMat("a*b: ",mmop("*",a,b))
   showMat("a/b: ",mmop("/",a,b))
   showMat("a^b: ",mmop("^",a,b))
   showMat("a+2: ",msop("+",a,2))
   showMat("a-2: ",msop("-",a,2))
   showMat("a*2: ",msop("*",a,2))
   showMat("a/2: ",msop("/",a,2))
   showMat("a^2: ",msop("^",a,2))
end

procedure mmop(op,A,B)
    if (*A = *B) & (*A[1] = *B[1]) then {
        C := [: |list(*A[1])\*A[1] :]
        a1 := create !!A
        b1 := create !!B
        every (!!C) := op(@a1,@b1)
        return C
        }
end

procedure msop(op,A,s)
    C := [: |list(*A[1])\*A[1] :]
    a1 := create !!A
    every (!!C) := op(@a1,s)
    return C
end

procedure showMat(label, m)
    every writes(label | right(!!m,5) | "\n")
end


T Point
   Float x, y

   F (x = Float.infinity, y = Float.infinity)
      .x = x
      .y = y

   F.const copy()
      R Point(.x, .y)

   F.const is_zero()
      R .x > 1e20 | .x < -1e20

   F neg()
      R Point(.x, -.y)

   F dbl()
      I .is_zero()
         R .copy()
      I .y == 0
         R Point()
      V l = (3 * .x * .x) / (2 * .y)
      V x = l * l - 2 * .x
      R Point(x, l * (.x - x) - .y)

   F add(q)
      I .x == q.x & .y == q.y
         R .dbl()
      I .is_zero()
         R q.copy()
      I q.is_zero()
         R .copy()
      I q.x - .x == 0
         R Point()
      V l = (q.y - .y) / (q.x - .x)
      V x = l * l - .x - q.x
      R Point(x, l * (.x - x) - .y)

   F mul(n)
      V p = .copy()
      V r = Point()
      V i = 1
      L i <= n
         I i [&] n
            r = r.add(p)
         p = p.dbl()
         i <<= 1
      R r

   F String()
      R ‘(#.3, #.3)’.format(.x, .y)

V Point_b = 7

F show(s, p)
   print(s‘ ’(I p.is_zero() {‘Zero’} E p))

F from_y(y)
   V n = y * y - Point_b
   V x = I n >= 0 {n ^ (1. / 3)} E -((-n) ^ (1. / 3))
   R Point(x, y)

V a = from_y(1)
V b = from_y(2)
show(‘a =’, a)
show(‘b =’, b)
V c = a.add(b)
show(‘c = a + b =’, c)
V d = c.neg()
show(‘d = -c =’, d)
show(‘c + d =’, c.add(d))
show(‘a + b + d =’, a.add(b.add(d)))
show(‘a * 12345 =’, a.mul(12345))


import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.stream.Stream;

@SuppressWarnings("serial")
public class ElementWiseOp {
	static final Map<String, BiFunction<Double, Double, Double>> OPERATIONS = new HashMap<String, BiFunction<Double, Double, Double>>() {
		{
			put("add", (a, b) -> a + b);
			put("sub", (a, b) -> a - b);
			put("mul", (a, b) -> a * b);
			put("div", (a, b) -> a / b);
			put("pow", (a, b) -> Math.pow(a, b));
			put("mod", (a, b) -> a % b);
		}
	};
	public static Double[][] scalarOp(String op, Double[][] matr, Double scalar) {
		BiFunction<Double, Double, Double> operation = OPERATIONS.getOrDefault(op, (a, b) -> a);
		Double[][] result = new Double[matr.length][matr[0].length];
		for (int i = 0; i < matr.length; i++) {
			for (int j = 0; j < matr[i].length; j++) {
				result[i][j] = operation.apply(matr[i][j], scalar);
			}
		}
		return result;
	}
	public static Double[][] matrOp(String op, Double[][] matr, Double[][] scalar) {
		BiFunction<Double, Double, Double> operation = OPERATIONS.getOrDefault(op, (a, b) -> a);
		Double[][] result = new Double[matr.length][Stream.of(matr).mapToInt(a -> a.length).max().getAsInt()];
		for (int i = 0; i < matr.length; i++) {
			for (int j = 0; j < matr[i].length; j++) {
				result[i][j] = operation.apply(matr[i][j], scalar[i % scalar.length][j
						% scalar[i % scalar.length].length]);
			}
		}
		return result;
	}
	public static void printMatrix(Double[][] matr) {
		Stream.of(matr).map(Arrays::toString).forEach(System.out::println);
	}
	public static void main(String[] args) {
		printMatrix(scalarOp("mul", new Double[][] {
				{ 1.0, 2.0, 3.0 },
				{ 4.0, 5.0, 6.0 },
				{ 7.0, 8.0, 9.0 }
		}, 3.0));

		printMatrix(matrOp("div", new Double[][] {
				{ 1.0, 2.0, 3.0 },
				{ 4.0, 5.0, 6.0 },
				{ 7.0, 8.0, 9.0 }
		}, new Double[][] {
				{ 1.0, 2.0},
				{ 3.0, 4.0}
		}));
	}
}


#include <stdio.h>
#include <math.h>

#define C 7
typedef struct { double x, y; } pt;

pt zero(void) { return (pt){ INFINITY, INFINITY }; }

// should be INFINITY, but numeric precision is very much in the way
int is_zero(pt p) { return p.x > 1e20 || p.x < -1e20; }

pt neg(pt p) { return (pt){ p.x, -p.y }; }

pt dbl(pt p) {
	if (is_zero(p)) return p;

	pt r;
	double L = (3 * p.x * p.x) / (2 * p.y);
	r.x = L * L - 2 * p.x;
	r.y = L * (p.x - r.x) - p.y;
	return r;
}

pt add(pt p, pt q) {
	if (p.x == q.x && p.y == q.y) return dbl(p);
	if (is_zero(p)) return q;
	if (is_zero(q)) return p;

	pt r;
	double L = (q.y - p.y) / (q.x - p.x);
	r.x = L * L - p.x - q.x;
	r.y = L * (p.x - r.x) - p.y;
	return r;
}

pt mul(pt p, int n) {
	int i;
	pt r = zero();

	for (i = 1; i <= n; i <<= 1) {
		if (i & n) r = add(r, p);
		p = dbl(p);
	}
	return r;
}

void show(const char *s, pt p) {
	printf("%s", s);
	printf(is_zero(p) ? "Zero\n" : "(%.3f, %.3f)\n", p.x, p.y);
}

pt from_y(double y) {
	pt r;
	r.x = pow(y * y - C, 1.0/3);
	r.y = y;
	return r;
}

int main(void) {
	pt a, b, c, d;

	a = from_y(1);
	b = from_y(2);

	show("a = ", a);
	show("b = ", b);
	show("c = a + b = ", c = add(a, b));
	show("d = -c = ", d = neg(c));
	show("c + d = ", add(c, d));
	show("a + b + d = ", add(a, add(b, d)));
	show("a * 12345 = ", mul(a, 12345));

	return 0;
}


# Occurrences of .[0] in "operator" will refer to an element in self,
# and occurrences of .[1] will refer to the corresponding element in other.
def elementwise( operator; other ):
  length as $rows
  | if $rows == 0 then .
    else . as $self
    | other as $other
    | ($self[0]|length) as $cols
    | reduce range(0; $rows) as $i
        ([]; reduce range(0; $cols) as $j
          (.; .[$i][$j] = ([$self[$i][$j], $other[$i][$j]] | operator) ) )
    end ;


#include <cmath>
#include <iostream>

using namespace std;

// define a type for the points on the elliptic curve that behaves
// like a built in type.
class EllipticPoint
{
    double m_x, m_y;
    static constexpr double ZeroThreshold = 1e20;
    static constexpr double B = 7; // the 'b' in y^2 = x^3 + a * x + b
                                  //  'a' is 0

    void Double() noexcept
    {
        if(IsZero())
        {
            // doubling zero is still zero
            return;
        }
        // based on the property of the curve, the line going through the
        // current point and the negative doubled point is tangent to the
        // curve at the current point.  wikipedia has a nice diagram.
        if(m_y == 0)
        {
            // at this point the tangent to the curve is vertical.
            // this point doubled is 0
            *this = EllipticPoint();
        }
        else
        {
            double L = (3 * m_x * m_x) / (2 * m_y);
            double newX = L * L -  2 * m_x;
            m_y = L * (m_x - newX) - m_y;
            m_x = newX;
        }
    }

public:
    friend std::ostream& operator<<(std::ostream&, const EllipticPoint&);

    // Create a point that is initialized to Zero
    constexpr EllipticPoint() noexcept : m_x(0), m_y(ZeroThreshold * 1.01) {}

    // Create a point based on the yCoordiante.  For a curve with a = 0 and b = 7
    // there is only one x for each y
    explicit EllipticPoint(double yCoordinate) noexcept
    {
        m_y = yCoordinate;
        m_x = cbrt(m_y * m_y - B);
    }

    // Check if the point is 0
    bool IsZero() const noexcept
    {
        // when the elliptic point is at 0, y = +/- infinity
        bool isNotZero =  abs(m_y) < ZeroThreshold;
        return !isNotZero;
    }

    // make a negative version of the point  (p = -q)
    EllipticPoint operator-() const noexcept
    {
        EllipticPoint negPt;
        negPt.m_x = m_x;
        negPt.m_y = -m_y;

        return negPt;
    }

    // add a point to this one  ( p+=q )
    EllipticPoint& operator+=(const EllipticPoint& rhs) noexcept
    {
        if(IsZero())
        {
            *this = rhs;
        }
        else if (rhs.IsZero())
        {
            // since rhs is zero this point does not need to be
            // modified
        }
        else
        {
            double L = (rhs.m_y - m_y) / (rhs.m_x - m_x);
            if(isfinite(L))
            {
                double newX = L * L - m_x - rhs.m_x;
                m_y = L * (m_x - newX) - m_y;
                m_x = newX;
            }
            else
            {
                if(signbit(m_y) != signbit(rhs.m_y))
                {
                    // in this case rhs == -lhs, the result should be 0
                    *this = EllipticPoint();
                }
                else
                {
                    // in this case rhs == lhs.
                    Double();
                }
            }
        }

        return *this;
    }

    // subtract a point from this one  (p -= q)
    EllipticPoint& operator-=(const EllipticPoint& rhs) noexcept
    {
        *this+= -rhs;
        return *this;
    }

    // multiply the point by an integer (p *= 3)
    EllipticPoint& operator*=(int rhs) noexcept
    {
        EllipticPoint r;
        EllipticPoint p = *this;

        if(rhs < 0)
        {
            // change p * -rhs to -p * rhs
            rhs = -rhs;
            p = -p;
        }

        for (int i = 1; i <= rhs; i <<= 1)
        {
            if (i & rhs) r += p;
            p.Double();
        }

        *this = r;
        return *this;
    }
};

// add points  (p + q)
inline EllipticPoint operator+(EllipticPoint lhs, const EllipticPoint& rhs) noexcept
{
    lhs += rhs;
    return lhs;
}

// subtract points  (p - q)
inline EllipticPoint operator-(EllipticPoint lhs, const EllipticPoint& rhs) noexcept
{
    lhs += -rhs;
    return lhs;
}

// multiply by an integer  (p * 3)
inline EllipticPoint operator*(EllipticPoint lhs, const int rhs) noexcept
{
    lhs *= rhs;
    return lhs;
}

// multiply by an integer (3 * p)
inline EllipticPoint operator*(const int lhs, EllipticPoint rhs) noexcept
{
    rhs *= lhs;
    return rhs;
}

// print the point
ostream& operator<<(ostream& os, const EllipticPoint& pt)
{
    if(pt.IsZero()) cout << "(Zero)\n";
    else cout << "(" << pt.m_x << ", " << pt.m_y << ")\n";
    return os;
}

int main(void) {
    const EllipticPoint a(1), b(2);
    cout << "a = " << a;
    cout << "b = " << b;
    const EllipticPoint c = a + b;
    cout << "c = a + b = "       << c;
    cout << "a + b - c = "       << a + b - c;
    cout << "a + b - (b + a) = " << a + b - (b + a) << "\n";

    cout << "a + a + a + a + a - 5 * a = "         << a + a + a + a + a - 5 * a;
    cout << "a * 12345 = "                         << a * 12345;
    cout << "a * -12345 = "                        << a * -12345;
    cout << "a * 12345 + a * -12345 = "            << a * 12345 + a * -12345;
    cout << "a * 12345 - (a * 12000 + a * 345) = " << a * 12345 - (a * 12000 + a * 345);
    cout << "a * 12345 - (a * 12001 + a * 345) = " << a * 12345 - (a * 12000 + a * 344) << "\n";

    const EllipticPoint zero;
    EllipticPoint g;
    cout << "g = zero = "      << g;
    cout << "g += a = "        << (g+=a);
    cout << "g += zero = "     << (g+=zero);
    cout << "g += b = "        << (g+=b);
    cout << "b + b - b * 2 = " << (b + b - b * 2) << "\n";

    EllipticPoint special(0);  // the point where the curve crosses the x-axis
    cout << "special = "      << special; // this has the minimum possible value for x
    cout << "special *= 2 = " << (special*=2); // doubling it gives zero

    return 0;
}


// version 1.1.51

typealias Matrix = Array<DoubleArray>
typealias Op = Double.(Double) -> Double

fun Double.dPow(exp: Double) = Math.pow(this, exp)

fun Matrix.elementwiseOp(other: Matrix, op: Op): Matrix {
    require(this.size == other.size && this[0].size == other[0].size)
    val result = Array(this.size) { DoubleArray(this[0].size) }
    for (i in 0 until this.size) {
        for (j in 0 until this[0].size) result[i][j] = this[i][j].op(other[i][j])
    }
    return result
}

fun Matrix.elementwiseOp(d: Double, op: Op): Matrix {
    val result = Array(this.size) { DoubleArray(this[0].size) }
    for (i in 0 until this.size) {
        for (j in 0 until this[0].size) result[i][j] = this[i][j].op(d)
    }
    return result
}

fun Matrix.print(name: Char?, scalar: Boolean? = false) {
    println(when (scalar) {
        true  -> "m $name s"
        false -> "m $name m"
        else  -> "m"
    } + ":")
    for (i in 0 until this.size) println(this[i].asList())
    println()
}

fun main(args: Array<String>) {
    val ops = listOf(Double::plus, Double::minus, Double::times, Double::div, Double::dPow)
    val names = "+-*/^"
    val m = arrayOf(
        doubleArrayOf(3.0, 5.0, 7.0),
        doubleArrayOf(1.0, 2.0, 3.0),
        doubleArrayOf(2.0, 4.0, 6.0)
    )
    m.print(null, null)
    for ((i, op) in ops.withIndex()) m.elementwiseOp(m, op).print(names[i])
    val s = 2.0
    println("s = $s:\n")
    for ((i, op) in ops.withIndex()) m.elementwiseOp(s, op).print(names[i], true)
}


import std.stdio, std.math, std.string;

enum bCoeff = 7;

struct Pt {
    double x, y;

    @property static Pt zero() pure nothrow @nogc @safe {
        return Pt(double.infinity, double.infinity);
    }

    @property bool isZero() const pure nothrow @nogc @safe {
        return x > 1e20 || x < -1e20;
    }

    @property static Pt fromY(in double y) nothrow /*pure*/ @nogc @safe {
        return Pt(cbrt(y ^^ 2 - bCoeff), y);
    }

    @property Pt dbl() const pure nothrow @nogc @safe {
        if (this.isZero)
            return this;
        immutable L = (3 * x * x) / (2 * y);
        immutable x2 = L ^^ 2  - 2 * x;
        return Pt(x2, L * (x - x2) - y);
    }

    string toString() const pure /*nothrow*/ @safe {
        if (this.isZero)
            return "Zero";
        else
            return format("(%.3f, %.3f)", this.tupleof);
    }

    Pt opUnary(string op)() const pure nothrow @nogc @safe
    if (op == "-") {
        return Pt(this.x, -this.y);
    }

    Pt opBinary(string op)(in Pt q) const pure nothrow @nogc @safe
    if (op == "+") {
        if (this.x == q.x && this.y == q.y)
            return this.dbl;
        if (this.isZero)
            return q;
        if (q.isZero)
            return this;
        immutable L = (q.y - this.y) / (q.x - this.x);
        immutable x = L ^^ 2 - this.x - q.x;
        return Pt(x, L * (this.x - x) - this.y);
    }

    Pt opBinary(string op)(in uint n) const pure nothrow @nogc @safe
    if (op == "*") {
        auto r = Pt.zero;
        Pt p = this;
        for (uint i = 1; i <= n; i <<= 1) {
            if ((i & n) != 0)
                r = r + p;
            p = p.dbl;
        }
        return r;
    }
}

void main() @safe {
    immutable a = Pt.fromY(1);
    immutable b = Pt.fromY(2);
    writeln("a = ", a);
    writeln("b = ", b);
    immutable c = a + b;
    writeln("c = a + b = ", c);
    immutable d = -c;
    writeln("d = -c = ", d);
    writeln("c + d = ", c + d);
    writeln("a + b + d = ", a + b + d);
    writeln("a * 12345 = ", a * 12345);
}


a = rand;
b = rand(10,10);
scalar_matrix = a * b;
component_wise = b .* b;


(require 'struct)
(decimals 4)
(string-delimiter "")
(struct pt (x y))

(define-syntax-id _.x (struct-get _ #:pt.x))
(define-syntax-id _.y (struct-get _ #:pt.y))

(define (E-zero) (pt Infinity Infinity))
(define (E-zero? p) (=  (abs p.x) Infinity))
(define (E-neg p) (pt  p.x  (- p.y)))

;; magic formulae from "C"
;; p + p
(define (E-dbl p)
	(if (E-zero? p) p
	(let* (
	[L (// (* 3 p.x p.x) (* 2 p.y))]
	[rx (- (* L L) (* 2 p.x))]
	[ry (- (* L (- p.x rx)) p.y)]
	)
	(pt rx ry))))

;; p + q
(define (E-add p q)
(cond
 [ (and (= p.x p.x) (= p.y q.y)) (E-dbl p)]
 [ (E-zero? p) q ]
 [ (E-zero? q) p ]
 [ else
 	(let* (
 	[L (// (- q.y p.y) (- q.x p.x))]
 	[rx (- (* L L) p.x q.x)] ;; match
 	[ry (- (* L (- p.x rx)) p.y)]
 	)
 	(pt rx ry))]))

 ;; (E-add* a b c ...)
(define (E-add* . pts) (foldl E-add (E-zero) pts))

;; p * n
(define (E-mul p n (r (E-zero)) (i 1))
	(while (<= i n)
		(when (!zero? (bitwise-and i n))  (set! r (E-add r p)))
		(set! p (E-dbl p))
		(set! i (* i 2)))
	r)

;; make points from x or y
(define (Ey.pt y  (c 7))
	(pt (expt (- (* y y) c) 1/3 ) y))
(define (Ex.pt x  (c 7))
	(pt x (sqrt (+ ( * x x x ) c))))

;; Check floating point precision
;; P * n is not always P+P+P+P....P

(define (E-ckmul a n )
	(define e a)
	(for ((i (in-range 1 n))) (set! e (E-add a e)))
	(printf "%d additions a+(a+(a+...)))  → %a" n e)
	(printf "multiplication a x %d        → %a" n (E-mul a n)))


import math, strutils

type Matrix[height, width: static Positive; T: SomeNumber] = array[height, array[width, T]]

####################################################################################################

proc `$`(m: Matrix): string =
  for i, row in m:
    var line = "["
    for j, val in row:
      line.addSep(" ", 1)
      line.add($val)
    line.add("]\n")
    result.add(line)

####################################################################################################
# Templates.

template elementWise(m1, m2: Matrix; op: proc(v1, v2: m1.T): auto): untyped =
  var result: Matrix[m1.height, m1.width, m1.T]
  for i in 0..<m1.height:
    for j in 0..<m1.width:
      result[i][j] = op(m1[i][j], m2[i][j])
  result

template scalarOp(m: Matrix; val: SomeNumber; op: proc(v1, v2: SomeNumber): auto): untyped =
  var result: Matrix[m.height, m.width, m.T]
  for i in 0..<m.height:
    for j in 0..<m.width:
      result[i][j] = op(m[i][j], val)
  result

template scalarOp(val: SomeNumber; m: Matrix; op: proc(v1, v2: SomeNumber): auto): untyped =
  var result: Matrix[m.height, m.width, m.T]
  for i in 0..<m.height:
    for j in 0..<m.width:
      result[i][j] = op(val, m[i][j])
  result

####################################################################################################
# Access functions.

func `[]`(m: Matrix; i, j: int): m.T =
  m[i][j]

func `[]=`(m: var Matrix; i, j: int; val: SomeNumber) =
  m[i][j] = val

####################################################################################################
# Elementwise operations.

func `+`(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, `+`)

func `-`(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, `-`)

func `*`(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, `*`)

func `div`(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, `div`)

func `mod`(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, `mod`)

func `/`(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, `/`)

func `^`(m1, m2: Matrix): Matrix =
  # Cannot use "elementWise" template as it requires both operator arguments
  # to be of type "m1.T" (and second argument of `^` is "Natural", not "int").
  for i in 0..<m1.height:
    for j in 0..<m1.width:
      result[i][j] = m1[i][j] ^ m2[i][j]

func pow(m1, m2: Matrix): Matrix =
  elementWise(m1, m2, pow)

####################################################################################################
# Matrix-scalar and scalar-matrix operations.

func `+`(m: Matrix; val: SomeNumber): Matrix =
  scalarOp(m, val, `+`)

func `+`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `+`)

func `-`(m: Matrix; val: SomeNumber): Matrix =
  scalarOp(m, val, `-`)

func `-`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `-`)

func `*`(m: Matrix; val: SomeNumber): Matrix =
  scalarOp(m, val, `*`)

func `*`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `*`)

func `div`(m: Matrix; val: SomeNumber): Matrix =
  scalarOp(m, val, `div`)

func `div`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `div`)

func `mod`(m: Matrix; val: m.T): Matrix =
  scalarOp(m, val, `mod`)

func `mod`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `mod`)

proc `/`(m: Matrix; val: SomeNumber): Matrix =
  scalarOp(m, val, `/`)

func `/`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `/`)

func `^`(m: Matrix; val: Natural): Matrix =
  # Cannot use "elementWise" template as it requires both operator arguments
  # to be of type "m.T" (and second argument of `^` is "Natural", not "int").
  for i in 0..<m.height:
    for j in 0..<m.width:
      result[i][j] = m[i][j] ^ val

func `^`(val: Natural; m: Matrix): Matrix =
  # Cannot use "elementWise" template as it requires both operator arguments
  # to be of type "m.T" (and second argument of `^` is "Natural", not "int").
  for i in 0..<m.height:
    for j in 0..<m.width:
      result[i][j] = val ^ m[i][j]

func pow(m: Matrix; val: SomeNumber): Matrix =
  scalarOp(m, val, pow)

func `pow`(val: SomeNumber; m: Matrix): Matrix =
  scalarOp(val, m, `pow`)

#———————————————————————————————————————————————————————————————————————————————————————————————————

# Operations on integer matrices.
let mint1: Matrix[2, 2, int] = [[1, 2], [3, 4]]
let mint2: Matrix[2, 2, int] = [[2, 1], [4, 2]]
echo "Integer matrices"
echo "----------------\n"
echo "m1:"
echo mint1
echo "m2:"
echo mint2
echo "m1 + m2"
echo mint1 + mint2
echo "m1 - m2"
echo mint1 - mint2
echo "m1 * m2"
echo mint1 * mint2
echo "m1 div m2"
echo mint1 div mint2
echo "m1 mod m2"
echo mint1 mod mint2
echo "m1^m2"
echo mint1^mint2
echo "2 * m1"
echo 2 * mint1
echo "m1 * 2"
echo mint1 * 2
echo "m1^2"
echo mint1 ^ 2
echo "2^m1"
echo 2 ^ mint1

# Operations on float matrices.
let mfloat1: Matrix[2, 3, float] = [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]
let mfloat2: Matrix[2, 3, float] = [[2.0, 2.0, 2.0], [3.0, 3.0, 3.0]]
echo "\nFloat matrices"
echo "--------------\n"
echo "m1"
echo mfloat1
echo "m2"
echo mfloat2
echo "m1 + m2"
echo mfloat1 + mfloat2
echo "m1 - m2"
echo mfloat1 - mfloat2
echo "m1 * m2"
echo mfloat1 * mfloat2
echo "m1 / m2"
echo mfloat1 / mfloat2
echo "pow(m1, m2)"
echo pow(mfloat1, mfloat2)
echo "pow(m1, 2.0)"
echo pow(mfloat1, 2.0)
echo "pow(2.0, m1)"
echo pow(2.0, mfloat1)


package main

import (
    "fmt"
    "math"
)

const bCoeff = 7

type pt struct{ x, y float64 }

func zero() pt {
    return pt{math.Inf(1), math.Inf(1)}
}

func is_zero(p pt) bool {
    return p.x > 1e20 || p.x < -1e20
}

func neg(p pt) pt {
    return pt{p.x, -p.y}
}

func dbl(p pt) pt {
    if is_zero(p) {
        return p
    }
    L := (3 * p.x * p.x) / (2 * p.y)
    x := L*L - 2*p.x
    return pt{
        x: x,
        y: L*(p.x-x) - p.y,
    }
}

func add(p, q pt) pt {
    if p.x == q.x && p.y == q.y {
        return dbl(p)
    }
    if is_zero(p) {
        return q
    }
    if is_zero(q) {
        return p
    }
    L := (q.y - p.y) / (q.x - p.x)
    x := L*L - p.x - q.x
    return pt{
        x: x,
        y: L*(p.x-x) - p.y,
    }
}

func mul(p pt, n int) pt {
    r := zero()
    for i := 1; i <= n; i <<= 1 {
        if i&n != 0 {
            r = add(r, p)
        }
        p = dbl(p)
    }
    return r
}

func show(s string, p pt) {
    fmt.Printf("%s", s)
    if is_zero(p) {
        fmt.Println("Zero")
    } else {
        fmt.Printf("(%.3f, %.3f)\n", p.x, p.y)
    }
}

func from_y(y float64) pt {
    return pt{
        x: math.Cbrt(y*y - bCoeff),
        y: y,
    }
}

func main() {
    a := from_y(1)
    b := from_y(2)
    show("a = ", a)
    show("b = ", b)
    c := add(a, b)
    show("c = a + b = ", c)
    d := neg(c)
    show("d = -c = ", d)
    show("c + d = ", add(c, d))
    show("a + b + d = ", add(a, add(b, d)))
    show("a * 12345 = ", mul(a, 12345))
}


import Data.Monoid
import Control.Monad (guard)
import Test.QuickCheck (quickCheck)


zero=: _j_

isZero=: 1e20 < |@{[email protected]+.

neg=: +

dbl=: monad define
  'p_x p_y'=. +. p=. y
  if. isZero p do. p return. end.
  L=. 1.5 * p_x*p_x % p_y
  r=. (L*L) - 2*p_x
  r j. (L * p_x-r) - p_y
)

add=: dyad define
  'p_x p_y'=. +. p=. x
  'q_x q_y'=. +. q=. y
  if. x=y do. dbl x return. end.
  if. isZero x do. y return. end.
  if. isZero y do. x return. end.
  L=. %~/ +. q-p
  r=. (L*L) - p_x + q_x
  r j. (L * p_x-r) - p_y
)

mul=: dyad define
  a=. zero
  for_bit.|.#:y do.
    if. bit do.
      a=. a add x
    end.
    x=. dbl x
  end.
  a
)

NB. C is 7
from=: j.~ [:(* * 3 |@%: ]) _7 0 1 p. ]

show=: monad define
  if. isZero y do. 'Zero' else.
    'a b'=. ":each +.y
    '(',a,', ', b,')'
  end.
)

task=: 3 :0
  a=. from 1
  b=. from 2

  echo 'a         = ', show a
  echo 'b         = ', show b
  echo 'c = a + b = ', show c =. a add b
  echo 'd = -c    = ', show d =. neg c
  echo 'c + d     = ', show c add d
  echo 'a + b + d = ', show add/ a, b, d
  echo 'a * 12345 = ', show a mul 12345
)


import static java.lang.Math.*;
import java.util.Locale;

public class Test {

    public static void main(String[] args) {
        Pt a = Pt.fromY(1);
        Pt b = Pt.fromY(2);
        System.out.printf("a = %s%n", a);
        System.out.printf("b = %s%n", b);
        Pt c = a.plus(b);
        System.out.printf("c = a + b = %s%n", c);
        Pt d = c.neg();
        System.out.printf("d = -c = %s%n", d);
        System.out.printf("c + d = %s%n", c.plus(d));
        System.out.printf("a + b + d = %s%n", a.plus(b).plus(d));
        System.out.printf("a * 12345 = %s%n", a.mult(12345));
    }
}

class Pt {
    final static int bCoeff = 7;

    double x, y;

    Pt(double x, double y) {
        this.x = x;
        this.y = y;
    }

    static Pt zero() {
        return new Pt(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
    }

    boolean isZero() {
        return this.x > 1e20 || this.x < -1e20;
    }

    static Pt fromY(double y) {
        return new Pt(cbrt(pow(y, 2) - bCoeff), y);
    }

    Pt dbl() {
        if (isZero())
            return this;
        double L = (3 * this.x * this.x) / (2 * this.y);
        double x2 = pow(L, 2) - 2 * this.x;
        return new Pt(x2, L * (this.x - x2) - this.y);
    }

    Pt neg() {
        return new Pt(this.x, -this.y);
    }

    Pt plus(Pt q) {
        if (this.x == q.x && this.y == q.y)
            return dbl();

        if (isZero())
            return q;

        if (q.isZero())
            return this;

        double L = (q.y - this.y) / (q.x - this.x);
        double xx = pow(L, 2) - this.x - q.x;
        return new Pt(xx, L * (this.x - xx) - this.y);
    }

    Pt mult(int n) {
        Pt r = Pt.zero();
        Pt p = this;
        for (int i = 1; i <= n; i <<= 1) {
            if ((i & n) != 0)
                r = r.plus(p);
            p = p.dbl();
        }
        return r;
    }

    @Override
    public String toString() {
        if (isZero())
            return "Zero";
        return String.format(Locale.US, "(%.3f,%.3f)", this.x, this.y);
    }
}


struct Point{T<:AbstractFloat}
    x::T
    y::T
end
Point{T}() where T<:AbstractFloat = Point{T}(Inf, Inf)
Point() = Point{Float64}()

Base.show(io::IO, p::Point{T}) where T = iszero(p) ? print(io, "Zero{$T}") : @printf(io, "{%s}(%.3f, %.3f)", T, p.x, p.y)
Base.copy(p::Point) = Point(p.x, p.y)
Base.iszero(p::Point{T}) where T = p.x in (-Inf, Inf)
Base.:-(p::Point) = Point(p.x, -p.y)

function dbl(p::Point{T}) where T
    iszero(p) && return p

    L = 3p.x ^ 2 / 2p.y
    x = L ^ 2 - 2p.x
    y = L * (p.x - x) - p.y
    return Point{T}(x, y)
end
Base.:(==)(a::Point{T}, C::Point{T}) where T = a.x == C.x && a.y == C.y

function Base.:+(p::Point{T}, q::Point{T}) where T
    p == q && return dbl(p)
    iszero(p) && return q
    iszero(q) && return p

    L = (q.y - p.y) / (q.x - p.x)
    x = L ^ 2 - p.x - q.x
    y = L * (p.x - x) - p.y
    return Point{T}(x, y)
end
function Base.:*(p::Point, n::Integer)
    r = Point()
    i = 1
    while i ≤ n
        if i & n != 0 r += p end
        p = dbl(p)
        i <<= 1
    end
    return r
end
Base.:*(n::Integer, p::Point) = p * n

const C = 7
function Point(y::AbstractFloat)
    n = y ^ 2 - C
    x = n ≥ 0 ? n ^ (1 / 3) : -((-n) ^ (1 / 3))
    return Point{typeof(y)}(x, y)
end

a = Point(1.0)
b = Point(2.0)
@show a b
@show c = a + b
@show d = -c
@show c + d
@show a + b + d
@show 12345a


// version 1.1.4

const val C = 7

class Pt(val x: Double, val y: Double) {
    val zero get() = Pt(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)

    val isZero get() = x > 1e20 || x < -1e20

    fun dbl(): Pt {
        if (isZero) return this
        val l = 3.0 * x * x / (2.0 * y)
        val t = l * l - 2.0 * x
        return Pt(t, l * (x - t) - y)
    }

    operator fun unaryMinus() = Pt(x, -y)

    operator fun plus(other: Pt): Pt {
        if (x == other.x && y == other.y) return dbl()
        if (isZero) return other
        if (other.isZero) return this
        val l = (other.y - y) / (other.x - x)
        val t = l * l - x - other.x
        return Pt(t, l * (x - t) - y)
    }

    operator fun times(n: Int): Pt {
        var r: Pt = zero
        var p = this
        var i = 1
        while (i <= n) {
            if ((i and n) != 0) r += p
            p = p.dbl()
            i = i shl 1
        }
        return r
    }

    override fun toString() =
        if (isZero) "Zero" else "(${"%.3f".format(x)}, ${"%.3f".format(y)})"
}

fun Double.toPt() = Pt(Math.cbrt(this * this - C), this)

fun main(args: Array<String>) {
    val a = 1.0.toPt()
    val b = 2.0.toPt()
    val c = a + b
    val d = -c
    println("a         = $a")
    println("b         = $b")
    println("c = a + b = $c")
    println("d = -c    = $d")
    println("c + d     = ${c + d}")
    println("a + b + d = ${a + b + d}")
    println("a * 12345 = ${a * 12345}")
}


(de elementWiseMatrix (Fun Mat1 Mat2)
   (mapcar '((L1 L2) (mapcar Fun L1 L2)) Mat1 Mat2) )

(de elementWiseScalar (Fun Mat Scalar)
   (elementWiseMatrix Fun Mat (circ (circ Scalar))) )


declare (matrix(3,3), vector(3), scalar) fixed;
declare (m(3,3), v(3) fixed;

m = scalar * matrix;
m = vector * matrix;
m = matrix * matrix;

v = scalar * vector;
v = vector * vector;


(* Task : Elliptic_curve_arithmetic *)

(*
    Using the secp256k1 elliptic curve (a=0, b=7),
    define the addition operation on points on the curve.
    Extra credit:   define the full elliptic curve arithmetic
    (still not modular, though) by defining a "multiply" function.
*)

(*** Helpers ***)

type ec_point = Point of float * float | Inf

type ec_curve = { a : float; b : float }

(* By default, cube root doesn't work for negative bases *)
let cube_root : float -> float =
    let third = 1. /. 3. in
    let f x =
        if x > 0.
        then x ** third
        else ~-. (~-. x ** third)
    in
    f

(* Finds the left-most x on this curve *)
let ec_minx ({a; b} : ec_curve) : float =
    let factor = ~-. b *. 0.5 in
    let discr = (factor ** 2.) +. (a ** 3. /. 27.) in
    if discr <= 0.
    then failwith "Not a simple curve"
    else
    let root = sqrt discr in
    cube_root (factor +. root) +. cube_root (factor -. root)

(* Negates the point by negating y coord *)
let ec_neg : ec_point -> ec_point = function
    | Inf -> Inf
    | Point (x, y) -> Point (x, ~-. y)

(*** Actual task at hand ***)

(* Generates a random point in the vicinity of x=0 *)
let ec_random ({a; b} as c : ec_curve) : ec_point =
    let minx = ec_minx c in
    let x = Random.float (~-. minx *. 2.) +. minx in
    let rhs = x ** 3. +. a *. x +. b in
    Point (x, sqrt rhs)

(*  Verifies that the point is on curve.
    Due to rounding errors, sometimes these calculations aren't perfect.
*)
let on_curve ?(debug : bool = false) ({a; b} : ec_curve) : ec_point -> bool = function
    | Inf -> true
    | Point (x, y) ->
        let lhs = y *. y in
        let rhs = x ** 3. +. a *. x +. b in
        let delta = abs_float (lhs -. rhs) in
        (
            if debug then Printf.printf "Delta = %.8f" delta;
            delta < 0.000001
        )

(* Doubles a point on the curve (adds a point to itself) *)
let ec_double ({a; b} as c : ec_curve) : ec_point -> ec_point = function
    | Inf -> Inf
    | Point (x, y) as p ->
        if not (on_curve c p)
        then failwith "Point not on this curve."
        else if y = 0.
        then Inf
        else
        let s = (3. *. x *. x +. a) /. (2. *. y) in
        let x' = s *. s -. 2. *. x in
        let y' = y +. s *. (x' -. x) in
        Point (x', -. y')

(* Adds any two points on the curve *)
let ec_add ({a; b} as c : ec_curve) (p : ec_point) (q : ec_point) : ec_point =
    match p, q with
    | Inf, x | x, Inf -> x
    | Point (px, py), Point (qx, qy) ->
        if not (on_curve c p) || not (on_curve c q)
        then failwith "Point not on this curve."
        else if abs_float (px -. qx) < 0.000001 then
        begin
            if abs_float (py +. qy) < 0.000001
            then Inf
            else
            (* py must equal qy here, otherwise something goes real bad *)
            ec_double c p |> ec_neg
        end
        else
        let s = (py -. qy) /. (px -. qx) in
        let rx = s *. s -. px -. qx in
        let ry = py +. s *. (rx -. px) in
        Point (rx, -. ry)

(* Extra credit : multiplies a point by a scalar *)
let ec_mul ({a; b} as c : ec_curve) (p : ec_point) (n : int) : ec_point =
    let rec helper n curPow acc =
        if n = 0 then acc
        else
        let doubled = ec_double c curPow in
        if n mod 2 = 0
        then helper (n / 2) doubled acc
        else helper (n / 2) doubled (ec_add c acc curPow)
    in
    helper n p Inf

(*** Output ***)

let string_of_point : ec_point -> string = function
    | Inf -> "Zero"
    | Point (x, y) -> Printf.sprintf "(%.4f, %.4f)" x y

let print_output () =
    let c = { a = 0.; b = 7. } in
    let p = ec_random c in
    let q = ec_random c in
    let r = ec_add c p q in
    let t = ec_neg r in
    Printf.printf "p = %s\n" (string_of_point p);
    Printf.printf "q = %s\n" (string_of_point q);
    Printf.printf "r = p + q = %s\n" (string_of_point r);
    Printf.printf "t = -r = %s\n" (string_of_point t);
    Printf.printf "r + t = %s\n" (ec_add c r t |> string_of_point);
    Printf.printf "p + (q + t) = %s\n" (ec_add c q t |> ec_add c p |> string_of_point);
    Printf.printf "p * 12345 = %s\n" (ec_mul c p 12345 |> string_of_point)

let _ =
    print_output ();
    print_output ()


# create a 2-times-2 matrix
mat <- matrix(1:4, 2, 2)

# matrix with scalar
mat + 2
mat * 2
mat ^ 2

# matrix with matrix
mat + mat
mat * mat
mat ^ mat


#lang racket(require math/array)

(define mat (list->array #(2 2) '(1 3 2 4)))

mat
(array+ mat (array 2))
(array* mat (array 2))
(array-map expt mat (array 2))

(array+ mat mat)
(array* mat mat)
(array-map expt mat mat)


my @a =
    [1,2,3],
    [4,5,6],
    [7,8,9];

sub msay(@x) {
    say .map( { ($_%1) ?? $_.nude.join('/') !! $_ } ).join(' ') for @x;
    say '';
}

msay @a «+» @a;
msay @a «-» @a;
msay @a «*» @a;
msay @a «/» @a;
msay @a «+» [1,2,3];
msay @a «-» [1,2,3];
msay @a «*» [1,2,3];
msay @a «/» [1,2,3];
msay @a «+» 2;
msay @a «-» 2;
msay @a «*» 2;
msay @a «/» 2;

# In addition to calling the underlying higher-order functions directly, it's possible to name a function.

sub infix:<M+> (\l,\r) { l <<+>> r }

msay @a M+ @a;
msay @a M+ [1,2,3];
msay @a M+ 2;


package EC;
{
    our ($A, $B) = (0, 7);
    package EC::Point;
    sub new { my $class = shift; bless [ @_ ], $class }
    sub zero { bless [], shift }
    sub x { shift->[0] }; sub y { shift->[1] };
    sub double {
        my $self = shift;
        return $self unless @$self;
        my $L = (3 * $self->x**2) / (2*$self->y);
        my $x = $L**2 - 2*$self->x;
        bless [ $x, $L * ($self->x - $x) - $self->y ], ref $self;
    }
    use overload
    '==' => sub { my ($p, $q) = @_; $p->x == $q->x and $p->y == $q->y },
    '+' => sub {
        my ($p, $q) = @_;
        return $p->double if $p == $q;
        return $p unless @$q;
        return $q unless @$p;
        my $slope = ($q->y - $p->y) / ($q->x - $p->x);
        my $x = $slope**2 - $p->x - $q->x;
        bless [ $x, $slope * ($p->x - $x)  - $p->y ], ref $p;
    },
    q{""} => sub {
        my $self = shift;
        return @$self
        ? sprintf "EC-point at x=%f, y=%f", @$self
        : 'EC point at infinite';
    }
}

package Test;
my $p = +EC::Point->new(-($EC::B - 1)**(1/3), 1);
my $q = +EC::Point->new(-($EC::B - 4)**(1/3), 2);
my $s = $p + $q, "\n";
print "$_\n" for $p, $q, $s;
print "check alignment... ";
print abs(($q->x - $p->x)*(-$s->y - $p->y) - ($q->y - $p->y)*($s->x - $p->x)) < 0.001
    ? "ok" : "wrong";


/*REXX program  multiplies two matrices together, displays the  matrices and the result.*/
m= (1 2 3)  (4 5 6)  (7 8 9)
w= words(m);                   do rows=1;       if rows*rows>=w  then leave
                               end   /*rows*/
cols= rows
call showMat  M, 'M matrix'
answer= matAdd(m, 2  );   call showMat answer, 'M matrix, added 2'
answer= matSub(m, 7  );   call showMat answer, 'M matrix, subtracted 7'
answer= matMul(m, 2.5);   call showMat answer, 'M matrix, multiplied by 2½'
answer= matPow(m, 3  );   call showMat answer, 'M matrix, cubed'
answer= matDiv(m, 4  );   call showMat answer, 'M matrix, divided by 4'
answer= matIdv(m, 2  );   call showMat answer, 'M matrix, integer halved'
answer= matMod(m, 3  );   call showMat answer, 'M matrix, modulus 3'
exit 0                                           /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
matAdd:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j+#;     end;  return [email protected]()
matSub:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j-#;     end;  return [email protected]()
matMul:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j*#;     end;  return [email protected]()
matDiv:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j/#;     end;  return [email protected]()
matIdv:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j%#;     end;  return [email protected]()
matPow:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j**#;    end;  return [email protected]()
matMod:   parse arg @,#;  call mat#;   do j=1  for w;  !.j= !.j//#;    end;  return [email protected]()
mat#:     w= words(@);                 do j=1  for w;  !.j= word(@,j); end;  return
[email protected]:     @= !.1;                      do j=2   to w;  @[email protected] !.j;        end;  return @
/*──────────────────────────────────────────────────────────────────────────────────────*/
showMat:  parse arg @, hdr;                    L= 0;                                 say
                               do j=1  for w;  L= max(L, length( word(@,j) ) ); end
          say  center(hdr, max( length(hdr)+4, cols * (L+1)+4), "─")
          n= 0
                  do     r=1  for rows;           _=
                      do c=1  for cols;  n= n+1;  _= _ right( word(@, n), L);   end; say _
                  end
          return


with javascript_semantics
constant X=1, Y=2, bCoeff=7, INF = 1e300*1e300

type point(object pt)
    return sequence(pt) and length(pt)=2 and atom(pt[X]) and atom(pt[Y])
end type

function zero()
    point pt = {INF, INF}
    return pt
end function

function is_zero(point p)
    return p[X]>1e20 or p[X]<-1e20
end function

function neg(point p)
    p = {p[X], -p[Y]}
    return p
end function

function dbl(point p)
    point r = p
    if not is_zero(p) then
        atom L = (3*p[X]*p[X])/(2*p[Y])
        atom x = L*L-2*p[X]
        r = {x, L*(p[X]-x)-p[Y]}
    end if
    return r
end function

function add(point p, point q)
    if p==q then return dbl(p) end if
    if is_zero(p) then return q end if
    if is_zero(q) then return p end if
    atom L = (q[Y]-p[Y])/(q[X]-p[X])
    atom x = L*L-p[X]-q[X]
    point r = {x, L*(p[X]-x)-p[Y]}
    return r
end function

function mul(point p, integer n)
    point r = zero()
    integer i = 1
    while i<=n do
        if and_bits(i, n) then r = add(r, p) end if
        p = dbl(p)
        i = i*2
    end while
    return r
end function

procedure show(string s, point p)
    puts(1, s&iff(is_zero(p)?"Zero\n":sprintf("(%.3f, %.3f)\n", p)))
end procedure

function cbrt(atom c)
    return iff(c>=0?power(c,1/3):-power(-c,1/3))
end function

function from_y(atom y)
    point r = {cbrt(y*y-bCoeff), y}
    return r
end function

point a, b, c, d

a = from_y(1)
b = from_y(2)
c = add(a, b)
d = neg(c)

show("a = ", a)
show("b = ", b)
show("c = a + b = ", c)
show("d = -c = ", d)
show("c + d = ", add(c, d))
show("a + b + d = ", add(a, add(b, d)))
show("a * 12345 = ", mul(a, 12345))


require 'matrix'

class Matrix
  def element_wise( operator, other )
    Matrix.build(row_size, column_size) do |row, col|
      self[row, col].send(operator, other[row, col])
    end
  end
end

m1, m2 = Matrix[[3,1,4],[1,5,9]], Matrix[[2,7,1],[8,2,2]]
puts "m1: #{m1}\nm2: #{m2}\n\n"

[:+, :-, :*, :/, :fdiv, :**, :%].each do |op|
  puts "m1 %-4s m2  =  %s" % [op, m1.element_wise(op, m2)]
end


struct Matrix {
    elements: Vec<f32>,
    pub height: u32,
    pub width: u32,
}

impl Matrix {
    fn new(elements: Vec<f32>, height: u32, width: u32) -> Matrix {
        // Should check for dimensions but omitting to be succient
        Matrix {
            elements: elements,
            height: height,
            width: width,
        }
    }

    fn get(&self, row: u32, col: u32) -> f32 {
        let row = row as usize;
        let col = col as usize;
        self.elements[col + row * (self.width as usize)]
    }

    fn set(&mut self, row: u32, col: u32, value: f32) {
        let row = row as usize;
        let col = col as usize;
        self.elements[col + row * (self.width as usize)] = value;
    }

    fn print(&self) {
        for row in 0..self.height {
            for col in 0..self.width {
                print!("{:3.0}", self.get(row, col));
            }
            println!("");
        }
        println!("");
    }
}

// Matrix addition will perform element-wise addition
fn matrix_addition(first: &Matrix, second: &Matrix) -> Result<Matrix, String> {
    if first.width == second.width && first.height == second.height {
        let mut result = Matrix::new(vec![0.0f32; (first.height * first.width) as usize],
                                     first.height,
                                     first.width);
        for row in 0..first.height {
            for col in 0..first.width {
                let first_value = first.get(row, col);
                let second_value = second.get(row, col);
                result.set(row, col, first_value + second_value);
            }
        }
        Ok(result)
    } else {
        Err("Dimensions don't match".to_owned())
    }
}

fn scalar_multiplication(scalar: f32, matrix: &Matrix) -> Matrix {
    let mut result = Matrix::new(vec![0.0f32; (matrix.height * matrix.width) as usize],
                                 matrix.height,
                                 matrix.width);
    for row in 0..matrix.height {
        for col in 0..matrix.width {
            let value = matrix.get(row, col);
            result.set(row, col, scalar * value);
        }
    }
    result
}

// Subtract second from first
fn matrix_subtraction(first: &Matrix, second: &Matrix) -> Result<Matrix, String> {
    if first.width == second.width && first.height == second.height {
        let negative_matrix = scalar_multiplication(-1.0, second);
        let result = matrix_addition(first, &negative_matrix).unwrap();
        Ok(result)
    } else {
        Err("Dimensions don't match".to_owned())
    }
}

// First must be a l x m matrix and second a m x n matrix for this to work.
fn matrix_multiplication(first: &Matrix, second: &Matrix) -> Result<Matrix, String> {
    if first.width == second.height {
        let mut result = Matrix::new(vec![0.0f32; (first.height * second.width) as usize],
                                     first.height,
                                     second.width);
        for row in 0..result.height {
            for col in 0..result.width {
                let mut value = 0.0;
                for it in 0..first.width {
                    value += first.get(row, it) * second.get(it, col);
                }
                result.set(row, col, value);
            }
        }
        Ok(result)
    } else {
        Err("Dimensions don't match. Width of first must equal height of second".to_owned())
    }
}

fn main() {
    let height = 2;
    let width = 3;
    // Matrix will look like:
    // | 1.0  2.0  3.0  |
    // | 4.0  5.0  6.0 |
    let matrix1 = Matrix::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], height, width);

    // Matrix will look like:
    // | 6.0  5.0  4.0  |
    // | 3.0  2.0  1.0 |
    let matrix2 = Matrix::new(vec![6.0, 5.0, 4.0, 3.0, 2.0, 1.0], height, width);

    // | 7.0  7.0  7.0  |
    // | 7.0  7.0  7.0 |
    matrix_addition(&matrix1, &matrix2).unwrap().print();
    // | 2.0   4.0   6.0  |
    // | 8.0  10.0  12.0 |
    scalar_multiplication(2.0, &matrix1).print();
    // | -5.0  -3.0  -1.0  |
    // |  1.0   3.0   5.0 |
    matrix_subtraction(&matrix1, &matrix2).unwrap().print();

    // | 1.0 |
    // | 1.0 |
    // | 1.0 |
    let matrix3 = Matrix::new(vec![1.0, 1.0, 1.0], width, 1);
    // |  6 |
    // | 15 |
    matrix_multiplication(&matrix1, &matrix3).unwrap().print();
}


var m1 = [[3,1,4],[1,5,9]]
var m2 = [[2,7,1],[8,2,2]]

say ":: Matrix-matrix operations"
say (m1 ~W+  m2)
say (m1 ~W-  m2)
say (m1 ~W*  m2)
say (m1 ~W/  m2)
say (m1 ~W// m2)
say (m1 ~W** m2)
say (m1 ~W%  m2)

say "\n:: Matrix-scalar operations"
say (m1 ~S+  42)
say (m1 ~S-  42)
say (m1 ~S/  42)
say (m1 ~S** 10)
# ...

say "\n:: Scalar-matrix operations"
say (m1 ~RS+  42)
say (m1 ~RS-  42)
say (m1 ~RS/  42)
say (m1 ~RS** 10)
# ...


(scl 16)
(load "@lib/math.l")
(setq *B 7)
(de from_y (Y)
   (let
      (A (* 1.0 (- (* Y Y) *B))
         B (pow (abs A) (*/ 1.0 1.0 3.0)) )
      (list
         (if (gt0 A) B (- B))
         (* Y 1.0) ) ) )
(de prn (P)
   (if (is_zero P)
      "Zero"
      (pack
         (round (car P) 3)
         " "
         (round (cadr P) 3) ) ) )
(de neg (P)
   (list (car P) (*/ -1.0 (cadr P) 1.0)) )
(de is_zero (P)
   (or
      (=T (car P))
      (=T (cadr P))
      (> (length (car P)) 20) ) )
(de dbl (P)
   (if (is_zero P)
      P
      (let
         (Y
            (*/
               1.0
               (*/ 3.0 (car P) (car P) (** 1.0 2))
               (*/ 2.0 (cadr P) 1.0) )
            X
            (-
               (*/ Y Y 1.0)
               (*/ 2.0 (car P) 1.0) ) )
         (list
            X
            (-
               (*/ Y (- (car P) X) 1.0)
               (cadr P) ) ) ) ) )
(de add (A B)
   (cond
      ((= A B) (dbl A))
      ((is_zero A) B)
      ((is_zero B) A)
      (T
         (let Z (- (car B) (car A))
            (if (=0 Z)
               (list T T)
               (let
                  (Y (*/ 1.0 (- (cadr B) (cadr A)) Z)
                     X
                     (- (*/ Y Y 1.0) (car A) (car B)) )
                  (list
                     X
                     (-
                        (*/ Y (- (car A) X) 1.0)
                        (cadr A) ) ) ) ) ) ) ) )
(de mul (P N)
   (let R (list T T)
      (for (I 1 (>= N I) (* I 2))
         (when (gt0 (& I N))
            (setq R (add R P)) )
         (setq P (dbl P)) )
      R ) )
(setq
   A (from_y 1)
   B (from_y 2) )
(prinl "A: " (prn A))
(prinl "B: " (prn B))
(setq C (add A B))
(prinl "C: " (prn C))
(setq D (neg C))
(prinl "D: " (prn D))
(prinl "D + C: " (prn (add C D)))
(prinl "A + B + D: " (prn (add A (add B D))))
(prinl "A * 12345: " (prn (mul A 12345)))


#!/usr/bin/env python3

class Point:
    b = 7
    def __init__(self, x=float('inf'), y=float('inf')):
        self.x = x
        self.y = y

    def copy(self):
        return Point(self.x, self.y)

    def is_zero(self):
        return self.x > 1e20 or self.x < -1e20

    def neg(self):
        return Point(self.x, -self.y)

    def dbl(self):
        if self.is_zero():
            return self.copy()
        try:
            L = (3 * self.x * self.x) / (2 * self.y)
        except ZeroDivisionError:
            return Point()
        x = L * L - 2 * self.x
        return Point(x, L * (self.x - x) - self.y)

    def add(self, q):
        if self.x == q.x and self.y == q.y:
            return self.dbl()
        if self.is_zero():
            return q.copy()
        if q.is_zero():
            return self.copy()
        try:
            L = (q.y - self.y) / (q.x - self.x)
        except ZeroDivisionError:
            return Point()
        x = L * L - self.x - q.x
        return Point(x, L * (self.x - x) - self.y)

    def mul(self, n):
        p = self.copy()
        r = Point()
        i = 1
        while i <= n:
            if i&n:
                r = r.add(p)
            p = p.dbl()
            i <<= 1
        return r

    def __str__(self):
        return "({:.3f}, {:.3f})".format(self.x, self.y)

def show(s, p):
    print(s, "Zero" if p.is_zero() else p)

def from_y(y):
    n = y * y - Point.b
    x = n**(1./3) if n>=0 else -((-n)**(1./3))
    return Point(x, y)

# demonstrate
a = from_y(1)
b = from_y(2)
show("a =", a)
show("b =", b)
c = a.add(b)
show("c = a + b =", c)
d = c.neg()
show("d = -c =", d)
show("c + d =", c.add(d))
show("a + b + d =", a.add(b.add(d)))
show("a * 12345 =", a.mul(12345))


structure Matrix = struct
local
    open Array2
    fun mapscalar f (x, scalar) =
	tabulate RowMajor (nRows x, nCols x, fn (i,j) => f(sub(x,i,j),scalar))
    fun map2 f (x, y) =
	tabulate RowMajor (nRows x, nCols x, fn (i,j) => f(sub(x,i,j),sub(y,i,j)))
in
infix splus sminus stimes
val op splus = mapscalar Int.+
val op sminus = mapscalar Int.-
val op stimes = mapscalar Int.*
val op + = map2 Int.+
val op - = map2 Int.-
val op * = map2 Int.*
val fromList = fromList
fun toList a =
    List.tabulate(nRows a, fn i => List.tabulate(nCols a, fn j => sub(a,i,j)))
end
end;

(* example *)
let open Matrix
    infix splus sminus stimes
    val m1 = fromList [[1,2],[3,4]]
    val m2 = fromList [[4,3],[2,1]]
    val s = 2
in
    List.map toList [m1+m2, m1-m2, m1*m2,
		     m1 splus s, m1 sminus s, m1 stimes s]
end;


mata
a = rnormal(5,5,0,1)
b = 2
a:+b
a:-b
a:*b
a:/b
a:^b

a = rnormal(5,5,0,1)
b = rnormal(5,1,0,1)
a:+b
a:-b
a:*b
a:/b
a:^b
end


package require Tcl 8.5
proc alias {name args} {uplevel 1 [list interp alias {} $name {} {*}$args]}

# Engine for elementwise operations between matrices
proc elementwiseMatMat {lambda A B} {
    set C {}
    foreach rA $A rB $B {
	set rC {}
	foreach vA $rA vB $rB {
	    lappend rC [apply $lambda $vA $vB]
	}
	lappend C $rC
    }
    return $C
}
# Lift some basic math ops
alias m+  elementwiseMatMat {{a b} {expr {$a+$b}}}
alias m-  elementwiseMatMat {{a b} {expr {$a-$b}}}
alias m*  elementwiseMatMat {{a b} {expr {$a*$b}}}
alias m/  elementwiseMatMat {{a b} {expr {$a/$b}}}
alias m** elementwiseMatMat {{a b} {expr {$a**$b}}}

# Engine for elementwise operations between a matrix and a scalar
proc elementwiseMatSca {lambda A b} {
    set C {}
    foreach rA $A {
	set rC {}
	foreach vA $rA {
	    lappend rC [apply $lambda $vA $b]
	}
	lappend C $rC
    }
    return $C
}
# Lift some basic math ops
alias .+  elementwiseMatSca {{a b} {expr {$a+$b}}}
alias .-  elementwiseMatSca {{a b} {expr {$a-$b}}}
alias .*  elementwiseMatSca {{a b} {expr {$a*$b}}}
alias ./  elementwiseMatSca {{a b} {expr {$a/$b}}}
alias .** elementwiseMatSca {{a b} {expr {$a**$b}}}


#lang racket
(define a 0) (define b 7)
(define (ε? x) (<= (abs x) 1e-14))
(define (== p q) (for/and ([pi p] [qi q]) (ε? (- pi qi))))
(define zero #(0 0))
(define (zero? p) (== p zero))
(define (neg p) (match-define (vector x y) p) (vector x (- y)))
(define (⊕ p q)
  (cond [(== q (neg p)) zero]
        [else
         (match-define (vector px py) p)
         (match-define (vector qx qy) q)
         (define (done λ px py qx)
           (define x (- (* λ λ) px qx))
           (vector x (- (+ (* λ (- x px)) py))))
         (cond [(and (== p q) (ε? py)) zero]
               [(or (== p q) (ε? (- px qx)))
                (done (/ (+ (* 3 px px) a) (* 2 py)) px py qx)]
               [(done (/ (- py qy) (- px qx)) px py qx)])]))
(define (⊗ p n)
  (cond [(= n 0)       zero]
        [(= n 1)       p]
        [(= n 2)       (⊕ p p)]
        [(negative? n) (neg (⊗ p (- n)))]
        [(even? n)     (⊗ (⊗ p (/ n 2)) 2)]
        [(odd? n)      (⊕ p (⊗ p (- n 1)))]))


unit module EC;
our ($A, $B) = (0, 7);

role Horizon { method gist { 'EC Point at horizon' } }
class Point {
    has ($.x, $.y);
    multi method new(
        $x, $y where $y**2 ~~ $x**3 + $A*$x + $B
    ) { self.bless(:$x, :$y) }
    multi method new(Horizon $) { self.bless but Horizon }
    method gist { "EC Point at x=$.x, y=$.y" }
}

multi prefix:<->(Point $p) { Point.new: x => $p.x, y => -$p.y }
multi prefix:<->(Horizon $) { Horizon }
multi infix:<->(Point $a, Point $b) { $a + -$b }

multi infix:<+>(Horizon $, Point $p) { $p }
multi infix:<+>(Point $p, Horizon) { $p }

multi infix:<*>(Point $u, Int $n) { $n * $u }
multi infix:<*>(Int $n, Horizon) { Horizon }
multi infix:<*>(0, Point) { Horizon }
multi infix:<*>(1, Point $p) { $p }
multi infix:<*>(2, Point $p) {
    my $l = (3*$p.x**2 + $A) / (2 *$p.y);
    my $y = $l*($p.x - my $x = $l**2 - 2*$p.x) - $p.y;
    $p.bless(:$x, :$y);
}
multi infix:<*>(Int $n where $n > 2, Point $p) {
    2 * ($n div 2 * $p) + $n % 2 * $p;
}

multi infix:<+>(Point $p, Point $q) {
    if $p.x ~~ $q.x {
        return $p.y ~~ $q.y ?? 2 * $p !! Horizon;
    }
    else {
        my $slope = ($q.y - $p.y) / ($q.x - $p.x);
        my $y = $slope*($p.x - my $x = $slope**2 - $p.x - $q.x) - $p.y;
        return $p.new(:$x, :$y);
    }
}

say my $p = Point.new: x => $_, y => sqrt(abs($_**3 + $A*$_ + $B)) given 1;
say my $q = Point.new: x => $_, y => sqrt(abs($_**3 + $A*$_ + $B)) given 2;
say my $s = $p + $q;

say "checking alignment:  ", abs ($p.x - $q.x)*(-$s.y - $q.y) - ($p.y - $q.y)*($s.x - $q.x);


import math

struct Matrix {
mut:
    ele    []f64
    stride int
}

fn matrix_from_rows(rows [][]f64) Matrix {
    if rows.len == 0 {
        return Matrix{[], 0}
    }
    mut m := Matrix{[]f64{len: rows.len*rows[0].len}, rows[0].len}
    for rx, row in rows {
		m.ele = m.ele[..rx*m.stride]
		m.ele << row
		m.ele << m.ele[(rx+1)*m.stride..]
    }
    return m
}

fn like(m Matrix) Matrix {
    return Matrix{[]f64{len: m.ele.len}, m.stride}
}

fn (m Matrix) str() string {
    mut s := ""
    for e := 0; e < m.ele.len; e += m.stride {
        s += "${m.ele[e..e+m.stride]} \n"
    }
    return s
}

type BinaryFunc64 = fn(f64, f64) f64

fn element_wise_mm(m1 Matrix, m2 Matrix, f BinaryFunc64) Matrix {
    mut z := like(m1)
    for i, m1e in m1.ele {
        z.ele[i] = f(m1e, m2.ele[i])
    }
    return z
}

fn element_wise_ms(m Matrix, s f64, f BinaryFunc64) Matrix {
    mut z := like(m)
    for i, e in m.ele {
        z.ele[i] = f(e, s)
    }
    return z
}

fn add(a f64, b f64) f64 { return a + b }
fn sub(a f64, b f64) f64 { return a - b }
fn mul(a f64, b f64) f64 { return a * b }
fn div(a f64, b f64) f64 { return a / b }
fn exp(a f64, b f64) f64 { return math.pow(a, b) }

fn add_matrix(m1 Matrix, m2 Matrix) Matrix { return element_wise_mm(m1, m2, add) }
fn sub_matrix(m1 Matrix, m2 Matrix) Matrix { return element_wise_mm(m1, m2, sub) }
fn mul_matrix(m1 Matrix, m2 Matrix) Matrix { return element_wise_mm(m1, m2, mul) }
fn div_matrix(m1 Matrix, m2 Matrix) Matrix { return element_wise_mm(m1, m2, div) }
fn exp_matrix(m1 Matrix, m2 Matrix) Matrix { return element_wise_mm(m1, m2, exp) }

fn add_scalar(m Matrix, s f64) Matrix { return element_wise_ms(m, s, add) }
fn sub_scalar(m Matrix, s f64) Matrix { return element_wise_ms(m, s, sub) }
fn mul_scalar(m Matrix, s f64) Matrix { return element_wise_ms(m, s, mul) }
fn div_scalar(m Matrix, s f64) Matrix { return element_wise_ms(m, s, div) }
fn exp_scalar(m Matrix, s f64) Matrix { return element_wise_ms(m, s, exp) }

fn h(heading string, m Matrix) {
    println(heading)
    print(m)
}

fn main() {
    m1 := matrix_from_rows([[f64(3), 1, 4], [f64(1), 5, 9]])
    m2 := matrix_from_rows([[f64(2), 7, 1], [f64(8), 2, 8]])
    h("m1:", m1)
    h("m2:", m2)
    println('')
    h("m1 + m2:", add_matrix(m1, m2))
    h("m1 - m2:", sub_matrix(m1, m2))
    h("m1 * m2:", mul_matrix(m1, m2))
    h("m1 / m2:", div_matrix(m1, m2))
    h("m1 ^ m2:", exp_matrix(m1, m2))
    println('')
    s := .5
    println("s: $s")
    h("m1 + s:", add_scalar(m1, s))
    h("m1 - s:", sub_scalar(m1, s))
    h("m1 * s:", mul_scalar(m1, s))
    h("m1 / s:", div_scalar(m1, s))
    h("m1 ^ s:", exp_scalar(m1, s))
}


import "/fmt" for Fmt
import "/matrix" for Matrix

// matrix-matrix element wise ops
class MM {
    static add(m1, m2) { m1 + m2 }
    static sub(m1, m2) { m1 - m2 }

    static mul(m1, m2) {
        if (!m1.sameSize(m2)) Fiber.abort("Matrices must be of the same size.")
        var m = Matrix.new(m1.numRows, m1.numCols)
        for (i in 0...m.numRows) {
            for (j in 0...m.numCols) m[i, j] = m1[i, j] * m2[i, j]
        }
        return m
    }

    static div(m1, m2) {
        if (!m1.sameSize(m2)) Fiber.abort("Matrices must be of the same size.")
        var m = Matrix.new(m1.numRows, m1.numCols)
        for (i in 0...m.numRows) {
            for (j in 0...m.numCols) m[i, j] = m1[i, j] / m2[i, j]
        }
        return m
    }

    static pow(m1, m2) {
        if (!m1.sameSize(m2)) Fiber.abort("Matrices must be of the same size.")
        var m = Matrix.new(m1.numRows, m1.numCols)
        for (i in 0...m.numRows) {
            for (j in 0...m.numCols) m[i, j] = m1[i, j].pow(m2[i, j])
        }
        return m
    }
}

// matrix-scalar element wise ops
class MS {
    static add(m, s) { m + s }
    static sub(m, s) { m - s }
    static mul(m, s) { m * s }
    static div(m, s) { m / s }
    static pow(m, s) { m.apply { |e| e.pow(s) } }
}

// scalar-matrix element wise ops
class SM {
    static add(s, m) {  m + s }
    static sub(s, m) { -m + s }
    static mul(s, m) {  m * s }

    static div(s, m) {
        var n = Matrix.new(m.numRows, m.numCols)
        for (i in 0...n.numRows) {
            for (j in 0...n.numCols) n[i, j] = s / m[i, j]
        }
        return n
    }

    static pow(s, m) {
        var n = Matrix.new(m.numRows, m.numCols)
        for (i in 0...n.numRows) {
            for (j in 0...n.numCols) n[i, j] = s.pow(m[i, j])
        }
        return n
    }
}

var m = Matrix.new([ [3, 5, 7], [1, 2, 3], [2, 4, 6] ])
System.print("m:")
Fmt.mprint(m, 2, 0)
System.print("\nm + m:")
Fmt.mprint(MM.add(m, m), 2, 0)
System.print("\nm - m:")
Fmt.mprint(MM.sub(m, m), 2, 0)
System.print("\nm * m:")
Fmt.mprint(MM.mul(m, m), 2, 0)
System.print("\nm / m:")
Fmt.mprint(MM.div(m, m), 2, 0)
System.print("\nm ^ m:")
Fmt.mprint(MM.pow(m, m), 6, 0)

var s = 2
System.print("\ns = %(s):")
System.print("\nm + s:")
Fmt.mprint(MS.add(m, s), 2, 0)
System.print("\nm - s:")
Fmt.mprint(MS.sub(m, s), 2, 0)
System.print("\nm * s:")
Fmt.mprint(MS.mul(m, s), 2, 0)
System.print("\nm / s:")
Fmt.mprint(MS.div(m, s), 3, 1)
System.print("\nm ^ s:")
Fmt.mprint(MS.pow(m, s), 2, 0)

System.print("\ns + m:")
Fmt.mprint(SM.add(s, m), 2, 0)
System.print("\ns - m:")
Fmt.mprint(SM.sub(s, m), 2, 0)
System.print("\ns * m:")
Fmt.mprint(SM.mul(s, m), 2, 0)
System.print("\ns / m:")
Fmt.mprint(SM.div(s, m), 8, 6)
System.print("\ns ^ m:")
Fmt.mprint(SM.pow(s, m), 3, 0)


/*REXX program defines (for any 2 points on the curve), returns the sum of the 2 points.*/
numeric digits 100                               /*try to ensure a min. of accuracy loss*/
a= func(1)             ;            say  '    a =              '          show(a)
b= func(2)             ;            say  '    b =              '          show(b)
c= add(a, b)           ;            say  '    c = (a+b)       ='          show(c)
d= neg(c)              ;            say  '    d = -c          ='          show(d)
e= add(c, d)           ;            say  '    e = (c+d)       ='          show(e)
g= add(a, add(b, d))   ;            say  '    g = (a+b+d)     ='          show(g)
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
cbrt:  procedure; parse arg x;                                            return root(x,3)
conv:  procedure; arg z; if isZ(z)  then return 'zero'; return left('',z>=0)format(z,,5)/1
root:  procedure; parse arg x,y;  if x=0 | y=1  then return x/1;   d=5;   return rootI()/1
rootG: parse value format(x,2,1,,0)  'E0'  with  ? 'E' _ .;    return (?/y'E'_ %y) + (x>1)
func:  procedure; parse arg y,k;  if k=='' then k=7;           return cbrt(y**2-k) y
inf:                                                           return '1e' || (digits()%2)
isZ:   procedure; parse arg px . ;                             return abs(px) >= inf()
neg:   procedure; parse arg px py;                             return px         (-py)
show:  procedure; parse arg x  y ;                             return conv(x)  conv(y)
zero:                                                          return inf()    inf()
/*──────────────────────────────────────────────────────────────────────────────────────*/
add:   procedure; parse arg px py, qx qy;     if px=qx & py=qy  then return dbl(px py)
       if isZ(px  py)  then return qx qy;     if isZ(qx qy)     then return     px py
       z= qx - px;       if z=0  then do;     $= inf();         rx= inf();         end
                                 else do;     $= (qy-py) / z;   rx= $*$ - px - qx; end
       ry= $ * (px-rx) - py;                                         return  rx  ry
/*──────────────────────────────────────────────────────────────────────────────────────*/
dbl:   procedure;  parse arg px py;      if isZ(px py)  then return px py;        z= py+py
                   if z=0  then $= inf()
                           else $= (3*px*py) / (py+py)
                   rx= $*$ - px*px;      ry= $ * (px-rx) - py;       return rx ry
/*──────────────────────────────────────────────────────────────────────────────────────*/
rootI: ox=x;  oy=y;  x=abs(x);  y=abs(y);  a=digits()+5;  numeric form;  g=rootG();  m=y-1
          do  until  d==a;    d=min(d+d,a);               numeric digits d;          o=0
            do  until o=g;    o=g;   g=format((m*g**y+x)/y/g**m,,d-2);  end  /*until o=g*/
          end  /*until d==a*/;       _=g*sign(ox);   if oy<0  then _=1/_;         return _


var [const] GSL=Import("zklGSL");	// libGSL (GNU Scientific Library)
M:=GSL.Matrix(3,3).set(3,5,7, 1,2,3, 2,4,6);
x:=2;
println("M = \n%s\nx = %s".fmt(M.format(),x));
foreach op in (T('+,'-,'*,'/)){
   println("M %s x:\n%s\n".fmt(op.toString()[3,1],op(M.copy(),x).format()));
}
foreach op in (T("addElements","subElements","mulElements","divElements")){
   println("M %s M:\n%s\n".fmt(op, M.copy().resolve(op)(M).format()));
}
mSqrd:=M.pump(0,M.copy(),fcn(x){ x*x });  // M element by element
println("M square elements:\n%s\n".fmt(mSqrd.format()));


Ellie = EllipticCurve(RR,[0,7]) # RR = field of real numbers

# a point (x,y) on Ellie, given y
def point ( y) :
    x = var('x')
    x = (y^2 - 7 - x^3).roots(x,ring=RR,multiplicities = False)[0]
    P = Ellie([x,y])
    return P

print(Ellie)
P = point(1)
print('P',P)
Q = point(2)
print('Q',Q)
S = P+Q
print('S = P + Q',S)
print('P+Q-S', P+Q-S)
print('P*12345' ,P*12345)


module EC {

    var A = 0
    var B = 7

    class Horizon {
        method to_s {
            "EC Point at horizon"
        }

        method *(_) {
            self
        }

        method -(_) {
            self
        }
    }

    class Point(Number x, Number y) {
        method to_s {
            "EC Point at x=#{x}, y=#{y}"
        }

        method neg {
            Point(x, -y)
        }

        method -(Point p) {
            self + -p
        }

        method +(Point p) {

            if (x == p.x) {
                return (y == p.y ? self*2 : Horizon())
            }
            else {
                var slope = (p.y - y)/(p.x - x)
                var x2 = (slope**2 - x - p.x)
                var y2 = (slope * (x - x2) - y)
                Point(x2, y2)
            }
        }

        method +(Horizon _) {
            self
        }

        method *((0)) {
            Horizon()
        }

        method *((1)) {
            self
        }

        method *((2)) {
            var l = (3 * x**2 + A)/(2 * y)
            var x2 = (l**2 - 2*x)
            var y2 = (l * (x - x2) - y)
            Point(x2, y2)
        }

        method *(Number n) {
            2*(self * (n>>1)) + self*(n % 2)
        }
    }

    class Horizon {
        method +(Point p) {
            p
        }
    }

    class Number {
        method +(Point p) {
            p + self
        }
        method *(Point p) {
            p * self
        }
        method *(Horizon h) {
            h
        }
        method -(Point p) {
            -p + self
        }
    }
}

say var p = with(1) {|v| EC::Point(v, sqrt(abs(1 - v**3 - EC::A*v - EC::B))) }
say var q = with(2) {|v| EC::Point(v, sqrt(abs(1 - v**3 - EC::A*v - EC::B))) }
say var s = (p + q)

say ("checking alignment:  ", abs((p.x - q.x)*(-s.y - q.y) - (p.y - q.y)*(s.x - q.x)) < 1e-20)


F ekg(n, limit)
   Set[Int] values
   assert(n >= 2)
   V r = [(1, 1), (2, n)]
   values.add(n)
   V i = 3
   V prev = n
   L i <= limit
      V val = 2
      L
         I val !C values & gcd(val, prev) != 1
            values.add(val)
            r [+]= (i, val)
            prev = val
            L.break
         val++
      i++
   R r

L(n) [2, 5, 7, 9, 10]
   [Int] result
   L(i, val) ekg(n, 10)
      result [+]= val
   print((‘EKG(’n‘):’).ljust(8)‘ ’result.join(‘, ’))

V ekg5 = [0] * 101
V ekg7 = [0] * 101
L(i, val) ekg(5, 100) {ekg5[i] = val}
L(i, val) ekg(7, 100) {ekg7[i] = val}
V convIndex = 0
L(i) 2..100
   I ekg5[i] == ekg7[i] & sorted(ekg5[1 .< i]) == sorted(ekg7[1 .< i])
      convIndex = i
      L.break
print(‘EKG(5) and EKG(7) converge at index ’convIndex‘.’)


set C 7
set zero {x inf y inf}
proc tcl::mathfunc::cuberoot n {
    # General power operator doesn't like negative, but its defined for root3
    expr {$n>=0 ? $n**(1./3) : -((-$n)**(1./3))}
}
proc iszero p {
    dict with p {}
    return [expr {$x > 1e20 || $x<-1e20}]
}
proc negate p {
    dict set p y [expr {-[dict get $p y]}]
}
proc double p {
    if {[iszero $p]} {return $p}
    dict with p {}
    set L [expr {(3.0 * $x**2) / (2.0 * $y)}]
    set rx [expr {$L**2 - 2.0 * $x}]
    set ry [expr {$L * ($x - $rx) - $y}]
    return [dict create x $rx y $ry]
}
proc add {p q} {
    if {[dict get $p x]==[dict get $q x] && [dict get $p y]==[dict get $q y]} {
	return [double $p]
    }
    if {[iszero $p]} {return $q}
    if {[iszero $q]} {return $p}

    dict with p {}
    set L [expr {([dict get $q y]-$y) / ([dict get $q x]-$x)}]
    dict set r x [expr {$L**2 - $x - [dict get $q x]}]
    dict set r y [expr {$L * ($x - [dict get $r x]) - $y}]
    return $r
}
proc multiply {p n} {
    set r $::zero
    for {set i 1} {$i <= $n} {incr i $i} {
	if {$i & int($n)} {
	    set r [add $r $p]
	}
	set p [double $p]
    }
    return $r
}


INCLUDE "D2:SORT.ACT" ;from the Action! Tool Kit

BYTE FUNC Contains(BYTE ARRAY a BYTE len,b)
  BYTE i

  IF len=0 THEN
    RETURN (0)
  FI
  FOR i=0 TO len-1
  DO
    IF a(i)=b THEN
      RETURN (1)
    FI
  OD
RETURN (0)

BYTE FUNC Gcd(BYTE a,b)
  BYTE tmp

  IF a<b THEN
    tmp=a a=b b=tmp
  FI

  WHILE b#0
  DO
    tmp=a MOD b
    a=b b=tmp
  OD
RETURN (a)

BYTE FUNC AreSame(BYTE ARRAY a,b BYTE len)
  BYTE i

  IF len=0 THEN
    RETURN (1)
  FI

  SortB(a,len,0)
  SortB(b,len,0)
  FOR i=0 TO len-1
  DO
    IF a(i)#b(i) THEN
      RETURN (0)
    FI
  OD
RETURN (1)

PROC CalcEkg(BYTE start,limit BYTE ARRAY ekg)
  BYTE len,i

  ekg(0)=1 ekg(1)=start
  FOR len=2 TO limit-1
  DO
    i=2
    DO
      IF Contains(ekg,len,i)=0 AND Gcd(ekg(len-1),i)>1 THEN
        ekg(len)=i
        EXIT
      FI
      i==+1
    OD
  OD
RETURN

BYTE FUNC CalcConvergence(BYTE ARRAY a,b BYTE len)
  BYTE i

  FOR i=2 TO len-1
  DO
    IF a(i)=b(i) AND AreSame(a,b,i)=1 THEN
      RETURN (i+1)
    FI
  OD
RETURN (0)

PROC PrintSeq(BYTE start BYTE ARRAY ekg BYTE len)
  BYTE i

  PrintF("EKG(%B)=",start)
  FOR i=0 TO len-1
  DO
    IF i>0 THEN Put(32) FI
    PrintB(ekg(i))
  OD
  PrintE("...")
RETURN

PROC Main()
  DEFINE PTR="CARD"
  DEFINE LIMIT="100"
  DEFINE SEQCOUNT="5"
  DEFINE PART="10"
  DEFINE EKG1="1"
  DEFINE EKG2="2"
  BYTE ARRAY buf(500),starts=[2 5 7 9 10]
  PTR ARRAY ekg(SEQCOUNT)
  BYTE i,conv

  Put(125) PutE() ;clear the screen

  FOR i=0 TO SEQCOUNT-1
  DO
    ekg(i)=buf+LIMIT*i
    CalcEkg(starts(i),LIMIT,ekg(i))
    PrintSeq(starts(i),ekg(i),PART)
  OD

  conv=CalcConvergence(ekg(EKG1),ekg(EKG2),LIMIT)
  PrintF("%EEKG(%B) and EKG(%B) ",starts(EKG1),starts(EKG2))
  IF conv=0 THEN
    PrintF("do not converge within %B items",LIMIT)
  ELSE
    PrintF("converge at index %B",conv)
  FI
RETURN


with Ada.Text_IO;
with Ada.Containers.Generic_Array_Sort;

procedure EKG_Sequences is

   type Element_Type is new Integer;

   type    Index_Type is new Integer range 1 .. 100;
   subtype Show_Range is Index_Type  range 1 .. 30;

   type Sequence is array (Index_Type range <>) of Element_Type;
   subtype EKG_Sequence is Sequence (Index_Type);

   function GCD (Left, Right : Element_Type) return Integer is
      A : Element_Type := Left;
      B : Element_Type := Right;
   begin
      while A /= B loop
         if A > B
         then A := A - B;
         else B := B - A;
         end if;
      end loop;
      return Integer (A);
   end GCD;

   function Contains (A    : Sequence;
                      B    : Element_Type;
                      Last : Index_Type) return Boolean
   is (for some Value of A (A'First .. Last) =>  Value = B);

   function Are_Same (S, T : EKG_Sequence; Last : Index_Type) return Boolean is
      S_Copy : Sequence := S (S'First .. Last);
      T_Copy : Sequence := T (T'First .. Last);
      procedure Sort is
        new Ada.Containers.Generic_Array_Sort (Index_Type   => Index_Type,
                                               Element_Type => Element_Type,
                                               Array_Type   => Sequence);
   begin
      Sort (S_Copy);
      Sort (T_Copy);
      return S_Copy = T_Copy;
   end Are_Same;

   function Create_EKG (Start : Element_Type) return EKG_Sequence is
      EKG : EKG_Sequence := (1 => 1, 2 => Start, others => 0);
   begin
      for N in 3 .. Index_Type'Last loop
         for I in 2 .. Element_Type'Last loop
            --  A potential sequence member cannot already have been used
            --  and must have a factor in common with previous member
            if not Contains (EKG, I, N)
              and then GCD (EKG (N - 1), I) > 1
            then
               EKG (N) := I;
               exit;
            end if;
         end loop;
      end loop;
      return EKG;
   end Create_EKG;

   procedure Converge (Seq_A, Seq_B : Sequence;
                       Term         : out Index_Type;
                       Do_Converge  : out Boolean) is
   begin
      for I in 3 .. Index_Type'Last loop
         if Seq_A (I) = Seq_B (I) and then Are_Same (Seq_A, Seq_B, I) then
            Do_Converge := True;
            Term        := I;
            return;
         end if;
      end loop;
      Do_Converge := False;
      Term        := Index_Type'Last;
   end Converge;

   procedure Put (Seq : Sequence) is
      use Ada.Text_IO;
   begin
      Put ("[");
      for E of Seq (Show_Range) loop
         Put (E'Image);
      end loop;
      Put ("]");
   end Put;

   use Ada.Text_IO;
   EKG_2  : constant EKG_Sequence := Create_EKG (2);
   EKG_5  : constant EKG_Sequence := Create_EKG (5);
   EKG_7  : constant EKG_Sequence := Create_EKG (7);
   EKG_9  : constant EKG_Sequence := Create_EKG (9);
   EKG_10 : constant EKG_Sequence := Create_EKG (10);
begin
   Put ("EKG( 2): ");  Put (EKG_2);  New_Line;
   Put ("EKG( 5): ");  Put (EKG_5);  New_Line;
   Put ("EKG( 7): ");  Put (EKG_7);  New_Line;
   Put ("EKG( 9): ");  Put (EKG_9);  New_Line;
   Put ("EKG(10): ");  Put (EKG_10); New_Line;

   --  Now compare EKG5 and EKG7 for convergence
   declare
      Term        : Index_Type;
      Do_Converge : Boolean;
   begin
      Converge (EKG_5, EKG_7, Term, Do_Converge);
      New_Line;
      if Do_Converge then
         Put_Line ("EKG(5) and EKG(7) converge at term "
                     & Term'Image);
      else
         Put_Line ("EKG5(5) and EKG(7) do not converge within "
                     & Term'Image & " terms");
      end if;
   end;
end EKG_Sequences;


import math

const b_coeff = 7

struct Pt {
	x f64
	y f64
}

fn zero() Pt {
    return Pt{math.inf(1), math.inf(1)}
}

fn is_zero(p Pt) bool {
    return p.x > 1e20 || p.x < -1e20
}

fn neg(p Pt) Pt {
    return Pt{p.x, -p.y}
}

fn dbl(p Pt) Pt {
    if is_zero(p) {
        return p
    }
    l := (3 * p.x * p.x) / (2 * p.y)
    x := l*l - 2*p.x
    return Pt{
        x: x,
        y: l*(p.x-x) - p.y,
    }
}

fn add(p Pt, q Pt) Pt {
    if p.x == q.x && p.y == q.y {
        return dbl(p)
    }
    if is_zero(p) {
        return q
    }
    if is_zero(q) {
        return p
    }
    l := (q.y - p.y) / (q.x - p.x)
    x := l*l - p.x - q.x
    return Pt{
        x: x,
        y: l*(p.x-x) - p.y,
    }
}

fn mul(mut p Pt, n int) Pt {
    mut r := zero()
    for i := 1; i <= n; i <<= 1 {
        if i&n != 0 {
            r = add(r, p)
        }
        p = dbl(p)
    }
    return r
}

fn show(s string, p Pt) {
    print("$s")
    if is_zero(p) {
        println("Zero")
    } else {
        println("(${p.x:.3f}, ${p.y:.3f})")
    }
}

fn from_y(y f64) Pt {
    return Pt{
        x: math.cbrt(y*y - b_coeff),
        y: y,
    }
}

fn main() {
    mut a := from_y(1)
    b := from_y(2)
    show("a = ", a)
    show("b = ", b)
    c := add(a, b)
    show("c = a + b = ", c)
    d := neg(c)
    show("d = -c = ", d)
    show("c + d = ", add(c, d))
    show("a + b + d = ", add(a, add(b, d)))
    show("a * 12345 = ", mul(mut a, 12345))
}


import "/fmt" for Fmt

var C = 7

class Pt {
    static zero { Pt.new(1/0, 1/0) }

    construct new(x, y) {
        _x = x
        _y = y
    }

    x { _x }
    y { _y }

    static fromNum(n) { Pt.new((n*n - C).cbrt, n) }

    isZero { x > 1e20 || x < -1e20 }

    double {
        if (isZero) return this
        var l = 3 * x * x / (2 * y)
        var t = l*l - 2*x
        return Pt.new(t, l*(x - t) - y)
    }

    - { Pt.new(x, -y) }

    +(other) {
        if (other.type != Pt) Fiber.abort("Argument must be a Pt object.")
        if (x == other.x && y == other.y) return double
        if (isZero) return other
        if (other.isZero) return this
        var l = (other.y - y) / (other.x - x)
        var t = l*l - x - other.x
        return Pt.new(t, l*(x-t) - y)
    }

    *(n) {
        if (n.type != Num || !n.isInteger) {
            Fiber.abort("Argument must be an integer.")
        }
        var r = Pt.zero
        var p = this
        var i = 1
        while (i <= n) {
            if ((i & n) != 0) r = r + p
            p = p.double
            i = i << 1
        }
        return r
    }

    toString { isZero ? "Zero" : Fmt.swrite("($0.3f, $0.3f)", x, y) }
}

var a = Pt.fromNum(1)
var b = Pt.fromNum(2)
var c = a + b
var d = -c
System.print("a         = %(a)")
System.print("b         = %(b)")
System.print("c = a + b = %(c)")
System.print("d = -c    = %(d)")
System.print("c + d     = %(c + d)")
System.print("a + b + d = %(a + b + d)")
System.print("a * 12345 = %(a * 12345)")


#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define FALSE 0
#define LIMIT 100

typedef int bool;

int compareInts(const void *a, const void *b) {
    int aa = *(int *)a;
    int bb = *(int *)b;
    return aa - bb;
}

bool contains(int a[], int b, size_t len) {
    int i;
    for (i = 0; i < len; ++i) {
        if (a[i] == b) return TRUE;
    }
    return FALSE;
}

int gcd(int a, int b) {
    while (a != b) {
        if (a > b)
            a -= b;
        else
            b -= a;
    }
    return a;
}

bool areSame(int s[], int t[], size_t len) {
    int i;
    qsort(s, len, sizeof(int), compareInts);
    qsort(t, len, sizeof(int), compareInts);
    for (i = 0; i < len; ++i) {
        if (s[i] != t[i]) return FALSE;
    }
    return TRUE;
}

int main() {
    int s, n, i;
    int starts[5] = {2, 5, 7, 9, 10};
    int ekg[5][LIMIT];
    for (s = 0; s < 5; ++s) {
        ekg[s][0] = 1;
        ekg[s][1] = starts[s];
        for (n = 2; n < LIMIT; ++n) {
            for (i = 2; ; ++i) {
                // a potential sequence member cannot already have been used
                // and must have a factor in common with previous member
                if (!contains(ekg[s], i, n) && gcd(ekg[s][n - 1], i) > 1) {
                    ekg[s][n] = i;
                    break;
                }
            }
        }
        printf("EKG(%2d): [", starts[s]);
        for (i = 0; i < 30; ++i) printf("%d ", ekg[s][i]);
        printf("\b]\n");
    }

    // now compare EKG5 and EKG7 for convergence
    for (i = 2; i < LIMIT; ++i) {
        if (ekg[1][i] == ekg[2][i] && areSame(ekg[1], ekg[2], i)) {
            printf("\nEKG(5) and EKG(7) converge at term %d\n", i + 1);
            return 0;
        }
    }
    printf("\nEKG5(5) and EKG(7) do not converge within %d terms\n", LIMIT);
    return 0;
}


const C=7, INFINITY=(0.0).inf;

fcn zero{ T(INFINITY, INFINITY) }

// should be INFINITY, but numeric precision is very much in the way
fcn is_zero(p){ x,_:=p; (x < -1e20 or x > 1e20) }

fcn neg(p){ return(p[0], -p[1]) }
fcn dbl(p){
   if(is_zero(p)) return(p);

   px,py := p;
   L:=(3.0 * px * px) / (2.0 * py);
   rx,ry := L * L - 2.0 * px, L * (px - rx) - py;
   return(rx,ry);
}

fcn add(p,q){
   px,py := p;
   qx,qy := q;
   if(px == qx and py == qy) return(dbl(p));
   if(is_zero(p)) return(q);
   if(is_zero(q)) return(p);

   L := (qy - py) / (qx - px);
   rx,ry := L * L - px - qx, L * (px - rx) - py;
   return(rx,ry);
}

fcn mul(p,n){
   r := zero();

   i:=1; while(i <= n){
      if(i.bitAnd(n)) r = add(r,p);
      p = dbl(p);
      i*=2;
   }
   r
}


// Generate EKG Sequences. Nigel Galloway: December 6th., 2018
let EKG            n=seq{
  let fN,fG=let    i=System.Collections.Generic.Dictionary<int,int>()
            let fN g=(if not (i.ContainsKey g) then i.[g]<-g);(g,i.[g])
            ((fun  e->i.[e]<-i.[e]+e), (fun  l->l|>List.map fN))
  let fU           l= pCache|>Seq.takeWhile(fun n->n<=l)|>Seq.filter(fun n->l%n=0)|>List.ofSeq
  let rec EKG l (α,β)=seq{let b=fU β in if (β=n||β<snd((fG b|>List.maxBy snd))) then fN α;        yield! EKG l (fG l|>List.minBy snd)
                                                                                else fN α;yield β;yield! EKG b (fG b|>List.minBy snd)}
  yield! seq[1;n]; let g=fU n in yield! EKG g (fG g|>Seq.minBy snd)}
let EKGconv n g=Seq.zip(EKG n)(EKG g)|>Seq.skip 2|>Seq.scan(fun(n,i,g,e)(l,β)->(Set.add l n,Set.add β i,l,β))(set[1;n],set[1;g],0,0)|>Seq.takeWhile(fun(n,i,g,e)->g<>e||n<>i)


USING: combinators.short-circuit formatting fry io kernel lists
lists.lazy math math.statistics prettyprint sequences
sequences.generalizations ;

: ekg? ( n seq -- ? )
    { [ member? not ] [ last gcd nip 1 > ] } 2&& ;

: (ekg) ( seq -- seq' )
    2 lfrom over [ ekg? ] curry lfilter car suffix! ;

: ekg ( n limit -- seq )
    [ 1 ] [ V{ } 2sequence ] [ 2 - [ (ekg) ] times ] tri* ;

: show-ekgs ( seq n -- )
    '[ dup _ ekg "EKG(%d) = %[%d, %]\n" printf ] each ;

: converge-at ( n m max -- o )
    tuck [ ekg [ cum-sum ] [ rest-slice ] bi ] [email protected]
    [ swapd [ = ] [email protected] and ] 4 nfind 4drop dup [ 2 + ] when ;

{ 2 5 7 9 10 } 20 show-ekgs nl
"EKG(5) and EKG(7) converge at term " write
5 7 100 converge-at .


package main

import (
    "fmt"
    "sort"
)

func contains(a []int, b int) bool {
    for _, j := range a {
        if j == b {
            return true
        }
    }
    return false
}

func gcd(a, b int) int {
    for a != b {
        if a > b {
            a -= b
        } else {
            b -= a
        }
    }
    return a
}

func areSame(s, t []int) bool {
    le := len(s)
    if le != len(t) {
        return false
    }
    sort.Ints(s)
    sort.Ints(t)
    for i := 0; i < le; i++ {
        if s[i] != t[i] {
            return false
        }
    }
    return true
}

func main() {
    const limit = 100
    starts := [5]int{2, 5, 7, 9, 10}
    var ekg [5][limit]int

    for s, start := range starts {
        ekg[s][0] = 1
        ekg[s][1] = start
        for n := 2; n < limit; n++ {
            for i := 2; ; i++ {
                // a potential sequence member cannot already have been used
                // and must have a factor in common with previous member
                if !contains(ekg[s][:n], i) && gcd(ekg[s][n-1], i) > 1 {
                    ekg[s][n] = i
                    break
                }
            }
        }
        fmt.Printf("EKG(%2d): %v\n", start, ekg[s][:30])
    }

    // now compare EKG5 and EKG7 for convergence
    for i := 2; i < limit; i++ {
        if ekg[1][i] == ekg[2][i] && areSame(ekg[1][:i], ekg[2][:i]) {
            fmt.Println("\nEKG(5) and EKG(7) converge at term", i+1)
            return
        }
    }
    fmt.Println("\nEKG5(5) and EKG(7) do not converge within", limit, "terms")
}


import Data.List (findIndex, isPrefixOf, tails)
import Data.Maybe (fromJust)

----------------------- EKG SEQUENCE ---------------------

seqEKGRec :: Int -> Int -> [Int] -> [Int]
seqEKGRec _ 0 l = l
seqEKGRec k n [] = seqEKGRec k (n - 2) [k, 1]
seqEKGRec k n l@(h : t) =
  seqEKGRec
    k
    (pred n)
    ( head
        ( filter
            (((&&) . flip notElem l) <*> ((1 <) . gcd h))
            [2 ..]
        ) :
      l
    )

seqEKG :: Int -> Int -> [Int]
seqEKG k n = reverse (seqEKGRec k n [])

--------------------- CONVERGENCE TEST -------------------
main :: IO ()
main =
  mapM_
    ( \x ->
        putStr "EKG ("
          >> (putStr . show $ x)
          >> putStr ") is "
          >> print (seqEKG x 20)
    )
    [2, 5, 7, 9, 10]
    >> putStr "EKG(5) and EKG(7) converge at "
    >> print
      ( succ $
          fromJust $
            findIndex
              (isPrefixOf (replicate 20 True))
              ( tails
                  ( zipWith
                      (==)
                      (seqEKG 7 80)
                      (seqEKG 5 80)
                  )
              )
      )


Until =: 2 :'u^:(0-:v)^:_'  NB. unused but so fun
prime_factors_of_tail =: [email protected]:q:@:{:
numbers_not_in_list =: -.~ >:@:[email protected]:(>./)

ekg =: 3 :0                             NB. return next sequence
 if. 1 = # y do. NB. initialize
  1 , y
  return.
 end.
 a =. prime_factors_of_tail y
 b =. numbers_not_in_list y
 index_of_lowest =. {. _ ,~ I. 1 e."1 a e."1 q:b
 if. index_of_lowest < _ do. NB. if the list doesn't need extension
  y , index_of_lowest { b
  return.
 end.
 NB. otherwise extend the list
 b =. >: >./ y
 while. 1 [email protected]:e. a e. q: b do.
  b =. >: b
 end.
 y , b
)

   ekg^:9&>2 5 7 9 10
1  2  4 6 3 9 12  8 10  5
1  5 10 2 4 6  3  9 12  8
1  7 14 2 4 6  3  9 12  8
1  9  3 6 2 4  8 10  5 15
1 10  2 4 6 3  9 12  8 14

assert 9 -: >:Until(>&8) 2
assert (,2) -: prime_factors_of_tail 6 8  NB. (nub of)
assert 3 4 5 -: numbers_not_in_list 1 2      6


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class EKGSequenceConvergence {

    public static void main(String[] args) {
        System.out.println("Calculate and show here the first 10 members of EKG[2], EKG[5], EKG[7], EKG[9] and EKG[10].");
        for ( int i : new int[] {2, 5, 7, 9, 10} ) {
            System.out.printf("EKG[%d] = %s%n", i, ekg(i, 10));
        }
        System.out.println("Calculate and show here at which term EKG[5] and EKG[7] converge.");
        List<Integer> ekg5 = ekg(5, 100);
        List<Integer> ekg7 = ekg(7, 100);
        for ( int i = 1 ; i < ekg5.size() ; i++ ) {
            if ( ekg5.get(i) == ekg7.get(i) && sameSeq(ekg5, ekg7, i)) {
                System.out.printf("EKG[%d](%d) = EKG[%d](%d) = %d, and are identical from this term on%n", 5, i+1, 7, i+1, ekg5.get(i));
                break;
            }
        }
    }

    //  Same last element, and all elements in sequence are identical
    private static boolean sameSeq(List<Integer> seq1, List<Integer> seq2, int n) {
        List<Integer> list1 = new ArrayList<>(seq1.subList(0, n));
        Collections.sort(list1);
        List<Integer> list2 = new ArrayList<>(seq2.subList(0, n));
        Collections.sort(list2);
        for ( int i = 0 ; i < n ; i++ ) {
            if ( list1.get(i) != list2.get(i) ) {
                return false;
            }
        }
        return true;
    }

    //  Without HashMap to identify seen terms, need to examine list.
    //    Calculating 3000 terms in this manner takes 10 seconds
    //  With HashMap to identify the seen terms, calculating 3000 terms takes .1 sec.
    private static List<Integer> ekg(int two, int maxN) {
        List<Integer> result = new ArrayList<>();
        result.add(1);
        result.add(two);
        Map<Integer,Integer> seen = new HashMap<>();
        seen.put(1, 1);
        seen.put(two, 1);
        int minUnseen = two == 2 ? 3 : 2;
        int prev = two;
        for ( int n = 3 ; n <= maxN ; n++ ) {
            int test = minUnseen - 1;
            while ( true ) {
                test++;
                if ( ! seen.containsKey(test) && gcd(test, prev) > 1 ) {

                    result.add(test);
                    seen.put(test, n);
                    prev = test;
                    if ( minUnseen == test ) {
                        do {
                            minUnseen++;
                        } while ( seen.containsKey(minUnseen) );
                    }
                    break;
                }
            }
        }
        return result;
    }

    private static final int gcd(int a, int b) {
        if ( b == 0 ) {
            return a;
        }
        return gcd(b, a%b);
    }

}


# jq optimizes the recursive call of _gcd in the following:
def gcd(a;b):
  def _gcd:
    if .[1] != 0 then [.[1], .[0] % .[1]] | _gcd else .[0] end;
  [a,b] | _gcd ;

def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;


using Primes

function ekgsequence(n, limit)
    ekg::Array{Int,1} = [1, n]
    while length(ekg) < limit
        for i in 2:2<<18
            if all(j -> j != i, ekg) && gcd(ekg[end], i) > 1
                push!(ekg, i)
                break
            end
        end
    end
    ekg
end

function convergeat(n, m, max = 100)
    ekgn = ekgsequence(n, max)
    ekgm = ekgsequence(m, max)
    for i in 3:max
        if ekgn[i] == ekgm[i] && sum(ekgn[1:i+1]) == sum(ekgm[1:i+1])
            return i
        end
    end
    warn("no converge in $max terms")
end

[println(rpad("EKG($i): ", 9), join(ekgsequence(i, 30), " ")) for i in [2, 5, 7, 9, 10]]
println("EKGs of 5 & 7 converge at term ", convergeat(5, 7))


// Version 1.2.60

fun gcd(a: Int, b: Int): Int {
    var aa = a
    var bb = b
    while (aa != bb) {
        if (aa > bb)
            aa -= bb
        else
            bb -= aa
    }
    return aa
}

const val LIMIT = 100

fun main(args: Array<String>) {
    val starts = listOf(2, 5, 7, 9, 10)
    val ekg = Array(5) { IntArray(LIMIT) }

    for ((s, start) in starts.withIndex()) {
        ekg[s][0] = 1
        ekg[s][1] = start
        for (n in 2 until LIMIT) {
            var i = 2
            while (true) {
                // a potential sequence member cannot already have been used
                // and must have a factor in common with previous member
                if (!ekg[s].slice(0 until n).contains(i) &&
                    gcd(ekg[s][n - 1], i) > 1) {
                        ekg[s][n] = i
                        break
                }
                i++
            }
        }
        System.out.printf("EKG(%2d): %s\n", start, ekg[s].slice(0 until 30))
    }

    // now compare EKG5 and EKG7 for convergence
    for (i in 2 until LIMIT) {
        if (ekg[1][i] == ekg[2][i] &&
        ekg[1].slice(0 until i).sorted() == ekg[2].slice(0 until i).sorted()) {
            println("\nEKG(5) and EKG(7) converge at term ${i + 1}")
            return
        }
    }
    println("\nEKG5(5) and EKG(7) do not converge within $LIMIT terms")
}


ClearAll[NextInSequence, EKGSequence]
NextInSequence[seq_List] := Module[{last, new = 1, holes, max, sel, found, i},
  last = Last[seq];
  max = Max[seq];
  holes = Complement[Range[max], seq];
  sel = SelectFirst[holes, Not[CoprimeQ[last, #]] &];
  If[MissingQ[sel],
   i = max;
   found = False;
   While[! found,
    i++;
    If[Not[CoprimeQ[last, i]],
     found = True
     ]
    ];
   Append[seq, i]
   ,
   Append[seq, sel]
  ]
 ]
EKGSequence[start_Integer, n_] := Nest[NextInSequence, {1, start}, n - 2]

Table[EKGSequence[s, 10], {s, {2, 5, 7, 9, 10}}] // Grid

s = Reverse[Transpose[{EKGSequence[5, 1000], EKGSequence[7, 1000]}]];
len = LengthWhile[s, Apply[Equal]];
s //= Reverse[Drop[#, len]] &;
Length[s] + 1


import algorithm, math, sets, strformat, strutils

#---------------------------------------------------------------------------------------------------

iterator ekg(n, limit: Positive): (int, int) =
  var values: HashSet[int]
  doAssert n >= 2
  yield (1, 1)
  yield (2, n)
  values.incl(n)
  var i = 3
  var prev = n
  while i <= limit:
    var val = 2
    while true:
      if val notin values and gcd(val, prev) != 1:
        values.incl(val)
        yield (i, val)
        prev = val
        break
      inc val
    inc i

#---------------------------------------------------------------------------------------------------

for n in [2, 5, 7, 9, 10]:
  var result: array[1..10, int]
  for i, val in ekg(n, 10): result[i] = val
  let title = fmt"EKG({n}):"
  echo fmt"{title:8} {result.join("", "")}"

var ekg5, ekg7: array[1..100, int]
for i, val in ekg(5, 100): ekg5[i] = val
for i, val in ekg(7, 100): ekg7[i] = val
var convIndex = 0
for i in 2..100:
  if ekg5[i] == ekg7[i] and sorted(ekg5[1..<i]) == sorted(ekg7[1..<i]):
    convIndex = i
    break
if convIndex > 0:
  echo fmt"EKG(5) and EKG(7) converge at index {convIndex}."
else:
  echo "No convergence found in the first {convIndex} terms."


use List::Util qw(none sum);

sub gcd { my ($u,$v) = @_; $v ? gcd($v, $u%$v) : abs($u) }
sub shares_divisors_with { gcd( $_[0], $_[1]) > 1 }

sub EKG {
    my($n,$limit) = @_;
    my @ekg = (1, $n);
    while (@ekg < $limit) {
        for my $i (2..1e18) {
            next unless none { $_ == $i } @ekg and shares_divisors_with($ekg[-1], $i);
            push(@ekg, $i) and last;
        }
    }
    @ekg;
}

sub converge_at {
    my($n1,$n2) = @_;
    my $max = 100;
    my @ekg1 = EKG($n1,$max);
    my @ekg2 = EKG($n2,$max);
    do { return $_+1 if $ekg1[$_] == $ekg2[$_] && sum(@ekg1[0..$_]) == sum(@ekg2[0..$_])} for 2..$max;
    return "(no convergence in $max terms)";
}

print "EKG($_): " . join(' ', EKG($_,10)) . "\n" for 2, 5, 7, 9, 10;
print "EKGs of 5 & 7 converge at term " . converge_at(5, 7) . "\n"


with javascript_semantics
constant LIMIT = 100
constant starts = {2, 5, 7, 9, 10}
sequence ekg = {}
string fmt = "EKG(%2d): ["&join(repeat("%d",min(LIMIT,30))," ")&"]\n"
for s=1 to length(starts) do
    ekg = append(ekg,{1,starts[s]}&repeat(0,LIMIT-2))
    for n=3 to LIMIT do
        -- a potential sequence member cannot already have been used
        -- and must have a factor in common with previous member
        integer i = 2
        while find(i,ekg[s])
           or gcd(ekg[s][n-1],i)<=1 do
            i += 1
        end while
        ekg[s][n] = i
    end for
    printf(1,fmt,starts[s]&ekg[s][1..min(LIMIT,30)])
end for

-- now compare EKG5 and EKG7 for convergence
constant EKG5 = find(5,starts),
         EKG7 = find(7,starts)
string msg = sprintf("do not converge within %d terms", LIMIT)
for i=3 to LIMIT do
    if ekg[EKG5][i]=ekg[EKG7][i]
    and sort(ekg[EKG5][1..i-1])=sort(ekg[EKG7][1..i-1]) then
        msg = sprintf("converge at term %d", i)
        exit
    end if
end for
printf(1,"\nEKG5(5) and EKG(7) %s\n", msg)