Category:Jq/polynomials.jq

From Rosetta Code
module {
  "name": "polynomials",
  "description": "Polynomials as JSON arrays",
  "version": "0.0.1",
  "homepage": "https://rosettacode.org/w/index.php?title=Category:Jq/polynomials.jq",
  "license": "MIT",
  "author": "pkoppstein at gmail dot com",
};

# Except for the above `module` declaration, this module is intended for use with jq, gojq and jaq,
# namely the C, Go and Rust implementations of jq.

# In this module, a point (x, y) in the Euclidean plane is represented by the JSON array [x, y],
# and the polynomial SIGMA a[i] * x^i is represented by the JSON array a.
# The canonical representation of a polynomical of degree n has length n+1,
# for example 2x is represented by [0,2].

# Unless otherwise indicated, all filters expect the canonical JSON representation
# of a polynomial as input. 

# The canonical form of the possibly non-canonical input polynomial
def canonical:
  if length == 0 then [0]
  elif length == 1 then .
  elif .[-1] == 0 then .[:-1]|canonical
  else .
  end;

# degree of the input polynomial, it being understood that
# [] | degree #=> null
def degree:
  canonical
  | length 
  | if . == 0 then null else . - 1 end;

# Evaluate the input polynomial at $x
# The input need not be canonical.
def eval($x):
  . as $p
  | reduce range(0; length) as $i ({power: 1, ans: 0};
      .ans += $p[$i] * .power
      | .power *= $x )
  | .ans;
  
# Add two polynomials and emit the canonical result.
def add($p1; $p2):
  ([($p1|length), ($p2|length)]|max) as $max
  | reduce range(0;$max) as $i ([range(0;$max)|0];
      .[$i] = $p1[$i] + $p2[$i])
  | canonical ;

# Multiply two polynomials. If they are canonical, the result will be too.
def multiply($p1; $p2):
  if $p1 == [0] or $p2 == [0] then [0]
  else
    reduce range(0;$p1|length) as $i ( [range(0; ($p1|length) + ($p2|length)) | 0];
      reduce range(0;$p2|length) as $j (.;
        .[$i+$j] += $p1[$i] * $p2[$j]))
  end;

# Multiply the input polynomial by a scalar.
def scalarMultiply($x):
  if $x == 0 then [0] else map($x * .) end;

# Divide the input polynomial by a scalar not 0
def scalarDivide($x): map(./$x);

# The derivative of an arbitrary polynomial.
def derivative:
  . as $p
  | if length == 1 then [0]
    else reduce range(0; length-1) as $i (.[1:];
      .[$i] = $p[$i+1] * ($i + 1) )
    end;

def pp:
  def digits: tostring | explode[] | [.] | implode | tonumber;
  def superscript:
    if . <= 1 then ""
    else ["\u2070", "\u00b9", "\u00b2", "\u00b3", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079"] as $ss
    | reduce digits as $d (""; . + $ss[$d] )
    end;

  . as $p
  | if length == 1 then .[0] | tostring
    else reduce range(0; length) as $i ([];
        if $p[$i] != 0
	then (if $i > 0 then "x" else "" end) as $x
        | ( if $i > 0 and ($p[$i]|length) == 1
	    then (if $p[$i] == 1 then "" else "-" end)
	    else ($p[$i]|tostring)
	    end ) as $c
	| . + ["\($c)\($x)\($i|superscript)"]
        else . end )
    | reverse
    | join("+")
    | gsub("\\+-"; "-")
    end ;

This category currently contains no pages or media.