Skip to content

Commit

Permalink
sampling over whole area coordinates. (#62)
Browse files Browse the repository at this point in the history
* sampling over whole area coordinates.

* added min_fuel and max_fuel sample params.

* fixed names.

* sampling pellets over circular areas.
  • Loading branch information
franciscojoray committed May 17, 2024
1 parent 1ac5910 commit 49b0a35
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 44 deletions.
2 changes: 1 addition & 1 deletion offchain/tests/admin/pellets/create-pellets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { createPellets } from "../../../transactions/admin/pellets/create-pellet
import { readPelletsCSV } from "./utils.ts";
import { printTxURL } from "../../../utils.ts";

const params = await readPelletsCSV("tests/admin/pellets.csv");
const params = await readPelletsCSV("tests/admin/pellets/pellets.csv");
const txHash = await createPellets(admin_token, params);
printTxURL(txHash);
12 changes: 9 additions & 3 deletions offchain/tests/admin/pellets/sample-pellets.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { getDiamondAreaSample, writePelletsCSV } from "./utils.ts";
import {
getRingAreaSample,
getDiamondAreaSample,
writePelletsCSV,
} from "./utils.ts";

const pellets = getDiamondAreaSample(20n, 30n, 0.15);
writePelletsCSV(pellets, "tests/admin/pellets/sample1.csv");
const pellets = getRingAreaSample(20, 30, 30n, 80n, 0.15);
//const pellets = getDiamondAreaSample(0n, 9n, 30n, 50n, 0.05);

writePelletsCSV(pellets, "tests/admin/pellets/circle1.csv");
152 changes: 112 additions & 40 deletions offchain/tests/admin/pellets/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { parse, stringify } from "jsr:@std/csv";

type Coordinates = Array<{ pos_x: bigint; pos_y: bigint }>;
type PelletParams = Array<{ fuel: number; pos_x: bigint; pos_y: bigint }>;

function getRandomSubarray<T>(arr: Array<T>, size: number) {
const shuffled = arr.slice(0);
let i = arr.length,
Expand All @@ -20,83 +23,147 @@ function getRandomSubarray<T>(arr: Array<T>, size: number) {
* actual "circumferences" (set of points equidistant from the center) in our geometry.
* @param r Diamond diagonal.
*/
function getDiamondCoordinates(
r: bigint
): Array<{ pos_x: bigint; pos_y: bigint }> {
const cs = [];
function getDiamondCoordinates(r: bigint): Coordinates {
const coordinates = [];
for (let i = 0n; i < r; i++) {
cs.push({
coordinates.push({
pos_x: r - i,
pos_y: i,
});
cs.push({
coordinates.push({
pos_x: -r + i,
pos_y: -i,
});
cs.push({
coordinates.push({
pos_x: -i,
pos_y: r - i,
});
cs.push({
coordinates.push({
pos_x: i,
pos_y: -r + i,
});
}
return cs;
return coordinates;
}

/**
* Returns an array with a random sample of pellet parameters on the perimeter
* of a diamond with diagonal r.
* @param r Diamond diagonal.
* @param density Density of the sample: equals 1 if every diamond point is taken. Must be in the range 0 - 1, inclusive.
* Returns an array with the coordinates of the points that lie in the
* area between two diamonds with diagonals inner_r and outer_r respectively.
* @param inner_r Inner diamond diagonal. Must be greater than or equal to 0.
* @param outer_r Outer diamond diagonal. Must be greater than or equal to inner_r.
*/
function getDiamondSample(
r: bigint,
density: number
): Array<{ fuel: number; pos_x: bigint; pos_y: bigint }> {
if (density > 1 || density < 0) {
throw Error("Density must be a number between 0 and 1.");
function getDiamondAreaCoordinates(
inner_r: bigint,
outer_r: bigint
): Coordinates {
if (inner_r < 0 || inner_r > outer_r) {
throw Error(
"inner_r must be a positive number less than or equal to outer_r"
);
}
const cs = getDiamondCoordinates(r);
const sample_size = Math.floor(cs.length * density);
const sample_cs = getRandomSubarray(cs, sample_size);
const pellets = sample_cs.map((c) => ({
fuel: Math.floor(Math.random() * 60 + 30), //random amount between 30 and 90.
pos_x: c.pos_x,
pos_y: c.pos_y,
}));
return pellets;
const coordinates = [];
for (let r = inner_r; r <= outer_r; r++) {
coordinates.push(getDiamondCoordinates(r));
}
return coordinates.flat();
}

/**
* Returns an array with a random sample of pellet parameters over the area
* between two diamonds with diagonals inner_r and outer_r respectively.
* @param inner_r Inner diamond diagonal. Must be greater than or equal to 0.
* @param Outer_r Outer diamond diagonal. Must be greater than or equal to inner_r.
* @param outer_r Outer diamond diagonal. Must be greater than or equal to inner_r.
* @param min_fuel Minimum fuel held by the sample pellets. Must be greater than or equal to 0.
* @param max_fuel Maximum fuel held by the sample pellets. Must be greater than or equal to min_fuel.
* @param density Density of the sample: equals 1 if every diamond point is taken. Must be in the range 0 - 1, inclusive.
*/
function getDiamondAreaSample(
inner_r: bigint,
outer_r: bigint,
min_fuel: bigint,
max_fuel: bigint,
density: number
): Array<{ fuel: number; pos_x: bigint; pos_y: bigint }> {
): PelletParams {
if (density > 1 || density < 0) {
throw Error("Density must be a number between 0 and 1.");
}
if (min_fuel < 0 || min_fuel > max_fuel) {
throw Error(
"min_fuel must be a positive number less than or equal to max_fuel"
);
}
const coordinates = getDiamondAreaCoordinates(inner_r, outer_r);
const sample_size = Math.floor(coordinates.length * density);
const sample_coordinates = getRandomSubarray(coordinates, sample_size);
const pellets = sample_coordinates.map((c) => ({
fuel: Math.floor(
Math.random() * Number(max_fuel - min_fuel) + Number(min_fuel)
),
pos_x: c.pos_x,
pos_y: c.pos_y,
}));
return pellets;
}

/**
* Returns an array with the coordinates of the points that lie in the
* area between two circles with radii inner_r and outer_r respectively.
* @param inner_r Inner circle radius. Must be greater than or equal to 0.
* @param outer_r Outer circle radius. Must be greater than or equal to inner_r.
*/
function getRingAreaCoordinates(inner_r: number, outer_r: number): Coordinates {
if (inner_r < 0 || inner_r > outer_r) {
throw Error(
"inner_r must be a positive number less than or equal to outer_r"
);
}
const pellets = [];
for (let r = inner_r; r <= outer_r; r++) {
pellets.push(getDiamondSample(r, density));
}
return pellets.flat();
const x_bound = Math.floor(outer_r);
const xs = Array.from({ length: 2 * x_bound + 1 }, (_, i) => i - x_bound);
const coordinates = xs.map((x) => {
const y_outer_bound = Math.floor(Math.sqrt(outer_r ** 2 - x ** 2));
let ys = Array.from(
{ length: 2 * y_outer_bound + 1 },
(_, i) => i - y_outer_bound
);
if (Math.abs(x) < Math.abs(inner_r)) {
const y_inner_bound = Math.floor(Math.sqrt(inner_r ** 2 - x ** 2));
ys = ys.filter((y) => Math.abs(y) > y_inner_bound);
}
return ys.map((y) => ({ pos_x: BigInt(x), pos_y: BigInt(y) }));
});
return coordinates.flat();
}

/**
* Returns an array with a random sample of pellet parameters over the area
* between two circles with radii inner_r and outer_r respectively.
* @param inner_r Inner diamond diagonal. Must be greater than or equal to 0.
* @param outer_r Outer diamond diagonal. Must be greater than or equal to inner_r.
* @param min_fuel Minimum fuel held by the sample pellets. Must be greater than or equal to 0.
* @param max_fuel Maximum fuel held by the sample pellets. Must be greater than or equal to min_fuel.
* @param density Density of the sample: equals 1 if every diamond point is taken. Must be in the range 0 - 1, inclusive.
*/
function getRingAreaSample(
inner_r: number,
outer_r: number,
min_fuel: bigint,
max_fuel: bigint,
density: number
): PelletParams {
const coordinates = getRingAreaCoordinates(inner_r, outer_r);
const sample_size = Math.floor(coordinates.length * density);
const sample_coordinates = getRandomSubarray(coordinates, sample_size);
const pellets = sample_coordinates.map((c) => ({
fuel: Math.floor(
Math.random() * Number(max_fuel - min_fuel) + Number(min_fuel)
),
pos_x: c.pos_x,
pos_y: c.pos_y,
}));
return pellets;
}

function writePelletsCSV(
pellets: Array<{ fuel: number; pos_x: bigint; pos_y: bigint }>,
path: string
) {
function writePelletsCSV(pellets: PelletParams, path: string) {
const csv = stringify(pellets, {
columns: ["fuel", "pos_x", "pos_y"],
});
Expand All @@ -119,4 +186,9 @@ async function readPelletsCSV(path: string) {
return params;
}

export { getDiamondAreaSample, writePelletsCSV, readPelletsCSV };
export {
getDiamondAreaSample,
getRingAreaSample,
writePelletsCSV,
readPelletsCSV,
};

0 comments on commit 49b0a35

Please sign in to comment.