Swapping Elements of a Slice (in-place) - vector

I have posted my solution in the answers below.
The question will not be updated with even more code to not further increase clutter.
I'm trying to rotate all elements in a Vec<Vec<T>> clockwise.
The vector is guaranteed to be square, as in v.len() == v[0].len().
The idea is to
find all elements that are equivalent under rotational symmetry to
v's center
swap these elements in place, using std::mem::swap
My current code does not change the state of the vec. How do I fix this?
fn rotate<T>(v: &mut Vec<Vec<T>>) {
// swap elements equivalent to position i on each ring r
// limit l = side length of current ring
//
// + 0 - - - - + r = 0 -> l = 6
// | + 1 - - + | r = 1 -> l = 4
// | | + 2 + | | r = 2 -> l = 2
// | | | | | |
// | | + - + | | swap:
// | + - - - + | a b c d
// + - - - - - + > b a c d
// > c a b d
// > d a b c
for r in 0..((v.len() + 1) / 2 {
let l = v.len() - 1 - r;
for i in r..l {
let mut a = & pieces[ r ][ r+i ];
let mut b = & pieces[ r+i ][ l-r ];
let mut c = & pieces[ l-r ][l-r-i];
let mut d = & pieces[l-r-i][ r ];
_rot_cw(&mut a, &mut b, &mut c, &mut d)},
}
}
fn _rot_cw<T>(a: &mut T, b: &mut T, c: &mut T, d: &mut T) {
//rotates a->b, b->c, c->d, d->a
std::mem::swap(a, b);
std::mem::swap(a, c);
std::mem::swap(a, d);
}
}
Edit:
Fixed minor issues in the original code above, thanks to #Jmb.
Here's my current code, again running into borrowing issues:
fn rotate_square_slice<T>(slice: &mut Vec<T>, rows: usize) {
for r in 0..(slice.len()+1)/2 {
let l = slice.len() -1 - r;
for i in r..l {
let a = &mut slice.get_mut(rows * r + r+i ).unwrap();
let b = &mut slice.get_mut(rows * (r+i) + l-r ).unwrap();
let c = &mut slice.get_mut(rows * (l-r) + l-r-i).unwrap();
let d = &mut slice.get_mut(rows * (l-r-i) + r ).unwrap();
std::mem::swap(a, b);
std::mem::swap(a, c);
std::mem::swap(a, d);
}
}
}

Swapping elements in a slice can be done by using the slice's swap() method.
Solving that problem, the code now looks like this:
fn rotate_square_slice<T>(slice: &mut [T], size: usize) {
for r in 0..(size + 1) / 2 {
let l = size - 1 - r;
for i in r..l {
// b, c & d are the indices with rotational symmetry to a,
// shifted by 90°, 180° & 270° respectively
let a = size * r + r+i ;
let b = size * (r+i) + l-r ;
let c = size * (l-r) + l-r-i;
let d = size * (l-r-i) + r ;
slice.swap(a, b);
slice.swap(a, c);
slice.swap(a, d);
}
}
}
I have, however, run into an issue with correctly indexing the slice. The question can be found here:
Rotational Symmetry Indexing in a 1D "Square" Array

Related

How to compare shapes of ndarrays in a concise way?

I'm new to Rust.
Suppose a matrix a has shape (n1, n2), b has (m1, m2), and c has (k1, k2). I would like to check that a and b can be multiplied (as matrices) and the shape of a * b is equal to c. In other words, (n2 == m1) && (n1 == k1) && (m2 == k2).
use ndarray::Array2;
// a : Array2<i64>
// b : Array2<i64>
// c : Array2<i64>
.shape method returns the shape of the array as a slice.
What is the concise way to do it?
Is the returned array from .shape() guaranteed to have length 2, or should I check it? If it guaranteed, is there a way to skip the None checking?
let n1 = a.shape().get(0); // this is Optional<i64>
For Array2 specifically there are .ncols() and .nrows() methods. If you are only working with 2d arrays then this is probably the best choice. They return usize, so no None checking is required.
use ndarray::prelude::*;
fn is_valid_matmul(a: &Array2<i64>, b: &Array2<i64>, c: &Array2<i64>) -> bool {
//nrows() and ncols() are only valid for Array2,
//[arr.nrows(), arr.ncols()] = [arr.shape()[0], arr.shape()[1]]
return a.ncols() == b.nrows() && b.ncols() == c.ncols() && a.nrows() == c.nrows();
}
fn main() {
let a = Array2::<i64>::zeros((3, 5));
let b = Array2::<i64>::zeros((5, 6));
let c_valid = Array2::<i64>::zeros((3, 6));
let c_invalid = Array2::<i64>::zeros((8, 6));
println!("is_valid_matmul(&a, &b, &c_valid) = {}", is_valid_matmul(&a, &b, &c_valid));
println!("is_valid_matmul(&a, &b, &c_invalid) = {}", is_valid_matmul(&a, &b, &c_invalid));
}
/*
output:
is_valid_matmul(&a, &b, &c_valid) = true
is_valid_matmul(&a, &b, &c_invalid) = false
*/

Why can't this struct method add an element to a vector through a mutable reference?

I have been trying to implement SHA256 as a practice, but I stumbled upon a behavior that I do not fully understand.
I start with a Vec<u8>, where I place the data to be hashed. Then, I pass a mutable reference to the hash function, where it adds the SHA2 padding. The problem is that when the push function is reached within the hash function, it does not add a thing.
I determined this behavior using the debugger, since the program does not crashes, just hangs in the while.
use std::fmt;
struct Sha256 {
state: [u32; 8],
k: [u32; 64]
}
impl fmt::Display for Sha256 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:x?}{:x?}{:x?}{:x?}{:x?}{:x?}{:x?}{:x?}",
self.state[0],self.state[1],self.state[2],self.state[3],
self.state[4],self.state[5],self.state[6],self.state[7]
)
}
}
impl Sha256 {
pub fn new() -> Sha256 {
Sha256 {
state: [
0x6a09e667,
0xbb67ae85,
0x3c6ef372,
0xa54ff53a,
0x510e527f,
0x9b05688c,
0x1f83d9ab,
0x5be0cd19
],
k: [
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]
}
}
pub fn process_block(&mut self, data: &[u8]) {
let mut w = [0u32; 64];
for (i, &d) in data.iter().enumerate() {
let byte = i % 4;
let word = i / 4;
w[word] |= (d as u32) << ((8*(3-byte)) as u32);
}
println!("{:?}", w);
for i in 16..64 {
let s0 = w[i-15].rotate_right(7) ^ w[i-15].rotate_right(18) ^ w[i-15].rotate_right(3);
let s1 = w[i-2].rotate_right(17) ^ w[i-2].rotate_right(19) ^ w[i-2].rotate_right(10);
w[i] = w[i-16].wrapping_add(s0).wrapping_add(w[i-7]).wrapping_add(s1);
}
let mut a = self.state[0];
let mut b = self.state[1];
let mut c = self.state[2];
let mut d = self.state[3];
let mut e = self.state[4];
let mut f = self.state[5];
let mut g = self.state[6];
let mut h = self.state[7];
for i in 0..64 {
let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
let ch = (e & f) ^((!e) & g);
let t1 = h.wrapping_add(s1).wrapping_add(ch).wrapping_add(self.k[i]).wrapping_add(w[i]);
let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
let maj = (a & b)^(a & c)^(b & c);
let t2 = s0.wrapping_add(maj);
h = g;
g = f;
f = e;
e = d.wrapping_add(t1);
d = c;
c = b;
b = a;
a = t1.wrapping_add(t2);
}
self.state[0] = self.state[0].wrapping_add(a);
self.state[1] = self.state[1].wrapping_add(b);
self.state[2] = self.state[2].wrapping_add(c);
self.state[3] = self.state[3].wrapping_add(d);
self.state[4] = self.state[4].wrapping_add(e);
self.state[5] = self.state[5].wrapping_add(f);
self.state[6] = self.state[6].wrapping_add(g);
self.state[7] = self.state[7].wrapping_add(h);
}
pub fn hash(&mut self, v: &mut Vec<u8>) {
v.push(0x80);
while (v.len()%64) < 56 {
v.push(0x00);
}
let size = v.len() as u64;
let mut s_idx = 0;
while s_idx < 8 {
let byte = ((size >> (8*(7-s_idx))) & 0xffu64 ) as u8;
s_idx += 1;
v.push(byte);
}
println!("{:?}", v);
for i in 0..(v.len()/64) {
self.process_block(&v[i*64..(i+1)*64]);
}
}
}
fn main() {
let mut th = Sha256::new();
let mut v = Vec::<u8>::new();
// Sha256::hash(&mut th, &mut v); // This not work
th.hash(&mut v); // Neither do this
println!("{}", th);
}
If I create another function I am able to push data within the function, like this:
fn add_elem(v: &mut Vec<u8>) {
v.push(10);
}
fn main() {
let mut th = Sha256::new();
let mut v = Vec::<u8>::new();
add_elem(&mut v);
th.hash(&mut v);
println!("{}", th);
}
I don't know what I am missing here, because the reference is the same, but it works sometimes and others not.
I am using the Rust 1.59 stable version for Linux and Windows (tested in both systems).
It seems to be a debugger error in this function, since the vector does in fact grow, but it cannot be seen by calling p v in the GDB console.

Modular inverses and unsigned integers

Modular inverses can be computed as follows (from Rosetta Code):
#include <stdio.h>
int mul_inv(int a, int b)
{
int b0 = b, t, q;
int x0 = 0, x1 = 1;
if (b == 1) return 1;
while (a > 1) {
q = a / b;
t = b, b = a % b, a = t;
t = x0, x0 = x1 - q * x0, x1 = t;
}
if (x1 < 0) x1 += b0;
return x1;
}
However, the inputs are ints, as you can see. Would the above code work for unsigned integers (e.g. uint64_t) as well? I mean, would it be ok to replaced all int with uint64_t? I could try for few inputs but it is not feasible to try for all 64-bits combinations.
I'm specifically interested in two aspects:
for values [0, 264) of both a and b, would all calculation not overflow/underflow (or overflow with no harm)?
how would (x1 < 0) look like in unsigned case?
First of all how this algorithm works? It is based on the Extended Euclidean algorithm for computation of the GCD. In short the idea is following: if we can find some integer coefficients m and n such that
a*m + b*n = 1
then m will be the answer for the modular inverse problem. It is easy to see because
a*m + b*n = a*m (mod b)
Luckily the Extended Euclidean algorithm does exactly that: if a and b are co-prime, it finds such m and n. It works in the following way: for each iteration track two triplets (ai, xai, yai) and (bi, xbi, ybi) such that at every step
ai = a0*xai + b0*yai
bi = a0*xbi + b0*ybi
so when finally the algorithm stops at the state of ai = 0 and bi = GCD(a0,b0), then
1 = GCD(a0,b0) = a0*xbi + b0*ybi
It is done using more explicit way to calculate modulo: if
q = a / b
r = a % b
then
r = a - q * b
Another important thing is that it can be proven that for positive a and b at every step |xai|,|xbi| <= b and |yai|,|ybi| <= a. This means there can be no overflow during calculation of those coefficients. Unfortunately negative values are possible, moreover, on every step after the first one in each equation one is positive and the other is negative.
What the code in your question does is a reduced version of the same algorithm: since all we are interested in is the x[a/b] coefficients, it tracks only them and ignores the y[a/b] ones. The simplest way to make that code work for uint64_t is to track the sign explicitly in a separate field like this:
typedef struct tag_uint64AndSign {
uint64_t value;
bool isNegative;
} uint64AndSign;
uint64_t mul_inv(uint64_t a, uint64_t b)
{
if (b <= 1)
return 0;
uint64_t b0 = b;
uint64AndSign x0 = { 0, false }; // b = 1*b + 0*a
uint64AndSign x1 = { 1, false }; // a = 0*b + 1*a
while (a > 1)
{
if (b == 0) // means original A and B were not co-prime so there is no answer
return 0;
uint64_t q = a / b;
// (b, a) := (a % b, b)
// which is the same as
// (b, a) := (a - q * b, b)
uint64_t t = b; b = a % b; a = t;
// (x0, x1) := (x1 - q * x0, x0)
uint64AndSign t2 = x0;
uint64_t qx0 = q * x0.value;
if (x0.isNegative != x1.isNegative)
{
x0.value = x1.value + qx0;
x0.isNegative = x1.isNegative;
}
else
{
x0.value = (x1.value > qx0) ? x1.value - qx0 : qx0 - x1.value;
x0.isNegative = (x1.value > qx0) ? x1.isNegative : !x0.isNegative;
}
x1 = t2;
}
return x1.isNegative ? (b0 - x1.value) : x1.value;
}
Note that if a and b are not co-prime or when b is 0 or 1, this problem has no solution. In all those cases my code returns 0 which is an impossible value for any real solution.
Note also that although the calculated value is really the modular inverse, simple multiplication will not always produce 1 because of the overflow at multiplication over uint64_t. For example for a = 688231346938900684 and b = 2499104367272547425 the result is inv = 1080632715106266389
a * inv = 688231346938900684 * 1080632715106266389 =
= 743725309063827045302080239318310076 =
= 2499104367272547425 * 297596738576991899 + 1 =
= b * 297596738576991899 + 1
But if you do a naive multiplication of those a and inv of type uint64_t, you'll get 4042520075082636476 so (a*inv)%b will be 1543415707810089051 rather than expected 1.
The mod_inv C function :
return a modular multiplicative inverse of n with respect to the modulus
return 0 if the linear congruence has no solutions
unsigned mod_inv(unsigned n, const unsigned mod) {
unsigned a = mod, b = a, c = 0, d = 0, e = 1, f, g;
for (n *= a > 1; n > 1 && (n *= a > 0); e = g, c = (c & 3) | (c & 1) << 2) {
g = d, d *= n / (f = a);
a = n % a, n = f;
c = (c & 6) | (c & 2) >> 1;
f = c > 1 && c < 6;
c = (c & 5) | (f || e > d ? (c & 4) >> 1 : ~c & 2);
d = f ? d + e : e > d ? e - d : d - e;
}
return n ? c & 4 ? b - e : e : 0;
}
Examples
n = 7 and mod = 45 then res = 13 so 1 == ( 13 * 7 ) % 45
n = 52 and mod = 107 then res = 35 so 1 == ( 35 * 52 ) % 107
n = 213 and mod = 155 then res = 147 so 1 == ( 147 * 213 ) % 155
n = 392 and mod = 45 then res = 38 so 1 == ( 38 * 392 ) % 45
n = 3708141711 and mod = 4280761040 it still works...

3d line-intersection code not working properly

I created this piece of code to get the intersection of two 3d line-segments.
Unfortunately the result of this code is inaccurate, the intersection-point is not always on both lines.
I am confused and unsure what I'm doing wrong.
Here is my code:
--dir = direction
--p1,p2 = represents the line
function GetIntersection(dirStart, dirEnd, p1, p2)
local s1_x, s1_y, s2_x, s2_y = dirEnd.x - dirStart.x, dirEnd.z - dirStart.z, p2.x - p1.x, p2.z - p1.z
local div = (-s2_x * s1_y) + (s1_x * s2_y)
if div == 0 then return nil end
local s = (-s1_y * (dirStart.x - p1.x) + s1_x * (dirStart.z - p1.z)) / div
local t = ( s2_x * (dirStart.z - p1.z) - s2_y * (dirStart.x - p1.x)) / div
if (s >= 0 and s <= 1 and t >= 0 and t <= 1) and (Vector(dirStart.x + (t * s1_x), 0, dirStart.z + (t * s1_y)) or nil) then
local v = Vector(dirStart.x + (t * s1_x),0,dirStart.z + (t * s1_y))
return v
end
end
This is example of Delphi code to find a distance between two skew lines in 3D. For your purposes it is necessary to check that result if small enough value (intersection does exist), check that s and t parameters are in range 0..1, then
calculate point using parameter s
Math of this approach is described in 'the shortest line...' section of Paul Bourke page
VecDiff if vector difference function, Dot id scalar product function
function LineLineDistance(const L0, L1: TLine3D; var s, t: Double): Double;
var
u: TPoint3D;
a, b, c, d, e, det, invdet:Double;
begin
u := VecDiff(L1.Base, L0.Base);
a := Dot(L0.Direction, L0.Direction);
b := Dot(L0.Direction, L1.Direction);
c := Dot(L1.Direction, L1.Direction);
d := Dot(L0.Direction, u);
e := Dot(L1.Direction, u);
det := a * c - b * b;
if det < eps then
Result := -1
else begin
invdet := 1 / det;
s := invdet * (b * e - c * d);
t := invdet * (a * e - b * d);
Result := Distance(PointAtParam(L0, s), PointAtParam(L1, t));
end;
end;
As far as I can tell your code is good. I've implemented this in javascript at https://jsfiddle.net/SalixAlba/kkrc9kcf/
and it seems to work for all the cases I can think of.
The only changes I've done is to change things to work in javascript rather than lua. The final condition was commented out
function GetIntersection(dirStart, dirEnd, p1, p2) {
var s1_x = dirEnd.x - dirStart.x;
var s1_y = dirEnd.z - dirStart.z;
var s2_x = p2.x - p1.x;
var s2_y = p2.z - p1.z;
var div = (-s2_x * s1_y) + (s1_x * s2_y);
if (div == 0)
return new Vector(0,0);
var s = (-s1_y * (dirStart.x - p1.x) + s1_x * (dirStart.z - p1.z)) / div;
var t = ( s2_x * (dirStart.z - p1.z) - s2_y * (dirStart.x - p1.x)) / div;
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
//and (Vector(dirStart.x + (t * s1_x), 0, dirStart.z + (t * s1_y)) or nil) then
var v = new Vector(
dirStart.x + (t * s1_x),
dirStart.z + (t * s1_y));
return v;
}
return new Vector(0,0);
}
Mathmatically it makes sense. If A,B and C,D are your two lines. Let s1 = B-A, s2 = C-D. A point of the line AB is given by A + t s1 and a point on the line CD is given by C + s s2. For an intersection we require
A + t s1 = C + s s2
or
(A-C) + t s1 = s s2
You two formula for s, t are found by taking the 2D cross product with each of the vectors s1 and s2
(A-C)^s1 + t s1^s1 = s s2^s1
(A-C)^s2 + t s1^s2 = s s2^s2
recalling s1^s1=s2^s2=0 and s2^s1= - s1^s2 we get
(A-C)^s1 = s s2^s1
(A-C)^s2 + t s1^s2 = 0
which can be solved to get s and t. This matches your equations.

F# adding polynomials recursively

I'm trying to write a function in F# that adds polynomials recursively. My polynomials can be represented as a list of tuples.
For example, 2x^4 + 3x^2 + x + 5 is equal to [(2.0,4);(3.0,2);(1.0,1);(5.0,0)]
All polynomials are properly structured (no repeated terms with the same degree, no terms with zero coefficients unless it is the zero polynomial, terms sorted by decreasing exponent no empty input list).
I'm having trouble doing this. Here is my code
type term = float * int
type poly = term list
let rec atp(t:term,p:poly):poly =
match p with
| [] -> []
| (a, b) :: tail -> if snd t = b then (fst t + a, b) :: [] elif snd t > b then t :: [] else ([]) :: atp(t, tail)
(* val atp : t:term * p:poly -> poly *)
let rec addpolys(p1:poly,p2:poly):poly =
match p1 with
| [] -> []
| (a,b) :: tail -> atp((a,b), p2) # addpolys(tail, p2)
I have two polynomials
val p2 : poly = [(4.5, 7); (3.0, 4); (10.5, 3); (2.25, 2)]
val p1 : poly = [(3.0, 5); (2.0, 2); (7.0, 1); (1.5, 0)]
and when I call the function, my result is
val p4 : poly =
[(4.5, 7); (3.0, 5); (3.0, 4); (3.0, 5); (10.5, 3); (3.0, 5); (4.25, 2)]
When the correct answer is
[(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
Unfortunately your code does not compile therefore it is difficult for me to understand your intentions. But I've got an own implementation for your problem. Maybe it will help you:
// addpoly: (float * 'a) list -> (float * 'a) list -> (float * 'a) list
let rec addpoly p1 p2 =
match (p1, p2) with
| [], p2 -> p2
| p1, [] -> p1
| (a1, n1)::p1s, (a2, n2)::p2s ->
if n1 < n2 then (a2, n2) :: addpoly p1 p2s
elif n1 > n2 then (a1, n1) :: addpoly p1s p2
else (a1+a2, n1) :: addpoly p1s p2s
let p1 = [(3.0, 5); (2.0, 2); ( 7.0, 1); (1.5, 0)]
let p2 = [(4.5, 7); (3.0, 4); (10.5, 3); (2.25, 2)]
let q = addpoly p1 p2
// val q : (float * int) list =
// [(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
I would like to make a little note. When you change the representation of the
polynomials a little bit then you can simplify the implementation of your function. You can express a polynomial as a list of its coefficients.
For example when you have this polynomial
p1 = 5.0x^5 + 2.0x^2 + 7.0x
you can write it also like this
p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
Therefore you are able to define the polynomial with this list:
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
Here are two functions which operates on the representation. polyval calculates the result for a given value and polyadd adds two polynomials. There implementation are rather simple:
// p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
// p2 = 0.0x^0 + 0.0x^1 + 2.25x^2 + 10.5x^3 + 3.0x^4 + 0.0x^5 + 0.0x^6 + 4.5x^7
let p2 = [0.0; 0.0; 2.25; 10.5; 3.0; 0.0; 0.0; 4.5]
// polyval: float list -> float -> float
let rec polyval ps x =
match ps with
| [] -> 0.0
| p::ps -> p + x * (polyval ps x)
// polyadd: float int -> float int -> float int
let rec polyadd ps qs =
match (ps, qs) with
| [], ys -> ys
| xs, [] -> xs
| x::xs, y::ys -> (x+y)::polyadd xs ys
let v = polyval p1 2.3
// val v : float = 349.99715
let p = polyadd p1 p2
// val p : float list = [1.5; 7.0; 4.25; 10.5; 3.0; 5.0; 0.0; 4.5]
Here's a completely generic, tail-recursive implementation:
let inline addPolys xs ys =
let rec imp acc = function
| (coeffx, degx)::xt, (coeffy, degy)::yt when degx = degy ->
imp ((coeffx + coeffy, degx)::acc) (xt, yt)
| (coeffx, degx)::xt, (coeffy, degy)::yt when degx > degy ->
imp ((coeffx, degx)::acc) (xt, (coeffy, degy)::yt)
| xs, yh::yt -> imp (yh::acc) (xs, yt)
| xh::xt, [] -> imp (xh::acc) (xt, [])
| [], yh::yt -> imp (yh::acc) ([], yt)
| [], [] -> acc
imp [] (xs, ys) |> List.rev
It has the type:
xs:( ^a * 'b) list -> ys:( ^a * 'b) list -> ( ^a * 'b) list
when ^a : (static member ( + ) : ^a * ^a -> ^a) and 'b : comparison
Since float has the member +, and int supports comparison, the type float * int matches these generic constraints:
> addPolys p1 p2;;
val it : (float * int) list =
[(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]

Resources