Skip to content

Commit 105f01a

Browse files
committed
test length of grid test actual
1 parent ebe1fdb commit 105f01a

8 files changed

+177
-13
lines changed

_util.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
/** Returns an array of length `n` containing elements `0` through `n - 1` */
22
export function range(n: number): number[] {
3-
const result = Array(n);
3+
if (!Number.isInteger(n)) {
4+
throw RangeError("n must be an integer");
5+
}
6+
const result = Array(Math.max(0, n));
47
for (let i = 0; i < n; i++) {
58
result[i] = i;
69
}
710
return result;
811
}
12+
13+
/** Return `n` factorial as an integer. */
14+
export function factorial(n: number): number {
15+
if (n < 0 || !Number.isInteger(n)) {
16+
throw RangeError("n must be a non-negative integer");
17+
}
18+
let result = 1;
19+
for (let i = 2; i <= n; i++) {
20+
result *= i;
21+
}
22+
return result;
23+
}

_util_test.ts

+75-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1-
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
2-
import { range } from "./_util.ts";
1+
import {
2+
assertEquals,
3+
assertStrictEquals,
4+
assertThrows,
5+
} from "https://deno.land/[email protected]/testing/asserts.ts";
6+
import { factorial, range } from "./_util.ts";
7+
8+
Deno.test("n = NaN", () => {
9+
assertThrows(() => range(NaN), RangeError, "n must be an integer");
10+
});
11+
12+
Deno.test("n = Infinity", () => {
13+
assertThrows(() => range(Infinity), RangeError, "n must be an integer");
14+
});
15+
16+
Deno.test("n = Math.PI", () => {
17+
assertThrows(() => range(Math.PI), RangeError, "n must be an integer");
18+
});
19+
20+
Deno.test("n = -1", () => {
21+
const actual = range(-1);
22+
assertEquals(actual, []);
23+
});
324

425
Deno.test("n = 0", () => {
526
const actual = range(0);
@@ -23,3 +44,55 @@ Deno.test("n = 10", () => {
2344
const expected = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
2445
assertEquals(actual, expected);
2546
});
47+
48+
Deno.test("n = NaN", () => {
49+
assertThrows(
50+
() => factorial(NaN),
51+
RangeError,
52+
"n must be a non-negative integer",
53+
);
54+
});
55+
56+
Deno.test("n < Infinity", () => {
57+
assertThrows(
58+
() => factorial(Infinity),
59+
RangeError,
60+
"n must be a non-negative integer",
61+
);
62+
});
63+
64+
Deno.test("n < Math.PI", () => {
65+
assertThrows(
66+
() => factorial(Math.PI),
67+
RangeError,
68+
"n must be a non-negative integer",
69+
);
70+
});
71+
72+
Deno.test("n < -1", () => {
73+
assertThrows(
74+
() => factorial(-1),
75+
RangeError,
76+
"n must be a non-negative integer",
77+
);
78+
});
79+
80+
Deno.test("n = 0", () => {
81+
const actual = factorial(0);
82+
assertStrictEquals(actual, 1);
83+
});
84+
85+
Deno.test("n = 1", () => {
86+
const actual = factorial(1);
87+
assertStrictEquals(actual, 1);
88+
});
89+
90+
Deno.test("n = 2", () => {
91+
const actual = factorial(2);
92+
assertStrictEquals(actual, 2);
93+
});
94+
95+
Deno.test("n = 10", () => {
96+
const actual = factorial(10);
97+
assertStrictEquals(actual, 3628800);
98+
});

combinations_test.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import {
22
assertEquals,
3+
assertStrictEquals,
34
assertThrows,
45
} from "https://deno.land/[email protected]/testing/asserts.ts";
56
import { combinations } from "./combinations.ts";
67
import { combinationsWithReplacement } from "./combinations_with_replacement.ts";
78
import { permutations } from "./permutations.ts";
8-
import { range } from "./_util.ts";
9+
import { factorial, range } from "./_util.ts";
910

1011
Deno.test("r = -1", () => {
1112
assertThrows(
@@ -61,13 +62,28 @@ for (let n = 0; n < 8; n++) {
6162
Deno.test(`combinations([${iterable}], ${r})`, () => {
6263
const actual = [...combinations(r, iterable)];
6364
const expected1 = [...combinations1(r, iterable)];
64-
const expected2 = [...combinations2(r, iterable)];
6565
assertEquals(actual, expected1);
66+
const expected2 = [...combinations2(r, iterable)];
6667
assertEquals(actual, expected2);
68+
const expectedLength = comb(iterable.length, r);
69+
assertStrictEquals(actual.length, expectedLength);
6770
});
6871
}
6972
}
7073

74+
/** Return the number of ways to choose `r` items from `n` items without repetition and without order. */
75+
function comb(n: number, r: number): number {
76+
if (n < 0 || !Number.isInteger(n)) {
77+
throw RangeError("n must be a non-negative integer");
78+
} else if (r < 0 || !Number.isInteger(r)) {
79+
throw RangeError("r must be a non-negative integer");
80+
} else if (r <= n) {
81+
return factorial(n) / (factorial(r) * factorial(n - r));
82+
} else {
83+
return 0;
84+
}
85+
}
86+
7187
/** Equivalent to `combinations` for testing. */
7288
export function* combinations1<T>(
7389
r: number,

combinations_with_replacement_test.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {
22
assertEquals,
3+
assertStrictEquals,
34
assertThrows,
45
} from "https://deno.land/[email protected]/testing/asserts.ts";
56
import { combinationsWithReplacement } from "./combinations_with_replacement.ts";
67
import { product } from "./product.ts";
7-
import { range } from "./_util.ts";
8+
import { factorial, range } from "./_util.ts";
89

910
Deno.test("r = -1", () => {
1011
assertThrows(
@@ -90,10 +91,27 @@ for (let n = 0; n < 6; n++) {
9091
const actual = [...combinationsWithReplacement(r, iterable)];
9192
const expected1 = [...combinationsWithReplacement1(r, iterable)];
9293
assertEquals(actual, expected1);
94+
const expectedLength = cwr(iterable.length, r);
95+
assertStrictEquals(actual.length, expectedLength);
9396
});
9497
}
9598
}
9699

100+
/** Return the number of ways to choose `r` items from `n` items with replacement and without order. */
101+
function cwr(n: number, r: number): number {
102+
if (n < 0 || !Number.isInteger(n)) {
103+
throw RangeError("n must be a non-negative integer");
104+
} else if (r < 0 || !Number.isInteger(r)) {
105+
throw RangeError("r must be a non-negative integer");
106+
} else if (r > n && n === 0) {
107+
return 0;
108+
} else if (r === 0) {
109+
return 1;
110+
} else {
111+
return factorial(n + r - 1) / (factorial(r) * factorial(n - 1));
112+
}
113+
}
114+
97115
/** Equivalent to `combinationsWithReplacement1` for testing. */
98116
function* combinationsWithReplacement1<T>(
99117
r: number,

permutations_test.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {
22
assertEquals,
3+
assertStrictEquals,
34
assertThrows,
45
} from "https://deno.land/[email protected]/testing/asserts.ts";
56
import { permutations } from "./permutations.ts";
67
import { product } from "./product.ts";
7-
import { range } from "./_util.ts";
8+
import { factorial, range } from "./_util.ts";
89

910
Deno.test("r = -1", () => {
1011
assertThrows(
@@ -86,16 +87,31 @@ for (let n = 0; n < 8; n++) {
8687
for (let r = 0; r < 6; r++) {
8788
Deno.test(`permutations([${iterable}], ${r})`, () => {
8889
const actual = [...permutations(r, iterable)];
89-
const expected1 = [...permutations1(iterable, r)];
90+
const expected1 = [...permutations1(r, iterable)];
9091
assertEquals(actual, expected1);
92+
const expectedLength = perm(iterable.length, r);
93+
assertStrictEquals(actual.length, expectedLength);
9194
});
9295
}
9396
}
9497

98+
/** Return the number of ways to choose `r` items from `n` items without replacement and with order. */
99+
function perm(n: number, r: number): number {
100+
if (n < 0 || !Number.isInteger(n)) {
101+
throw RangeError("n must be a non-negative integer");
102+
} else if (r < 0 || !Number.isInteger(r)) {
103+
throw RangeError("r must be a non-negative integer");
104+
} else if (r > n) {
105+
return 0;
106+
} else {
107+
return factorial(n) / factorial(n - r);
108+
}
109+
}
110+
95111
/** Equivalent to `permutations` for testing. */
96112
function* permutations1<T>(
97-
iterable: Iterable<T>,
98113
r: number,
114+
iterable: Iterable<T>,
99115
): Generator<T[]> {
100116
const pool = [...iterable];
101117
const n = pool.length;

power_set.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { range } from "./_util.ts";
22

3-
/** Yields all successive subsets of input `iterable`. */
3+
/** Yields every subset of elements from `iterable`. */
44
export function* powerSet<T>(iterable: Iterable<T>): Generator<T[]> {
55
const pool = [...iterable];
66
const n = pool.length;

power_set_test.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
1+
import {
2+
assertEquals,
3+
assertStrictEquals,
4+
} from "https://deno.land/[email protected]/testing/asserts.ts";
25
import { combinations } from "./combinations.ts";
36
import { combinations1, combinations2 } from "./combinations_test.ts";
47
import { powerSet } from "./power_set.ts";
@@ -40,14 +43,25 @@ for (let i = 0; i < 8; i++) {
4043
Deno.test(`powerSet([${iterable}])`, () => {
4144
const actual = [...powerSet(iterable)];
4245
const expected1 = [...powerSet1(iterable)];
43-
const expected2 = [...powerSet2(iterable)];
44-
const expected3 = [...powerSet3(iterable)];
4546
assertEquals(actual, expected1);
47+
const expected2 = [...powerSet2(iterable)];
4648
assertEquals(actual, expected2);
49+
const expected3 = [...powerSet3(iterable)];
4750
assertEquals(actual, expected3);
51+
const expectedLength = ps(iterable.length);
52+
assertStrictEquals(actual.length, expectedLength);
4853
});
4954
}
5055

56+
/** Return the number of subsets of a set with `n` elements. */
57+
function ps(n: number): number {
58+
if (n < 0 || !Number.isInteger(n)) {
59+
throw RangeError("n must be a non-negative integer");
60+
} else {
61+
return Math.pow(2, n);
62+
}
63+
}
64+
5165
/** Equivalent to `powerSet` for testing. */
5266
function* powerSet1<T>(iterable: Iterable<T>): Generator<T[]> {
5367
const pool = [...iterable];

product_test.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
assertEquals,
3+
assertStrictEquals,
34
assertThrows,
45
} from "https://deno.land/[email protected]/testing/asserts.ts";
56
import { product } from "./product.ts";
@@ -133,6 +134,8 @@ for (let elements = 1; elements < 10; elements += 0.1) {
133134
const actual = [...product(r, ...iterables)];
134135
const expected1 = [...product1(r, ...iterables)];
135136
assertEquals(actual, expected1);
137+
const expectedLength = prod(r, iterables.map(({ length }) => length));
138+
assertStrictEquals(actual.length, expectedLength);
136139
});
137140
}
138141

@@ -141,6 +144,15 @@ function randRange(stop: number): number {
141144
return Math.floor(Math.random() * stop);
142145
}
143146

147+
/** Calculate the product of all the elements of the input `iterable` repeated `r` times. */
148+
function prod(r: number, iterable: Iterable<number>): number {
149+
let product = 1;
150+
for (const factor of iterable) {
151+
product *= factor;
152+
}
153+
return Math.pow(product, r);
154+
}
155+
144156
/** Equivalent to `product` for testing. */
145157
function* product1<T>(r: number, ...iterables: Iterable<T>[]): Generator<T[]> {
146158
const pools: T[][] = Array(r)

0 commit comments

Comments
 (0)