Skip to content

Commit 7050b48

Browse files
committed
tensor and table support
1 parent 64aef17 commit 7050b48

File tree

20 files changed

+433
-55
lines changed

20 files changed

+433
-55
lines changed

packages/hedgehog-core/.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"bracketSpacing": true,
1717
"jsxBracketSameLine": true,
1818
"alwaysParens":"avoid",
19-
"@typescript-eslint/ban-ts-ignore": "off"
19+
"@typescript-eslint/ban-ts-ignore": "off",
20+
"endOfLine": "auto"
2021
}
2122
]
2223
}

packages/hedgehog-core/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@
2828
"@tensorflow/tfjs": "^2.7.0",
2929
"babel-template": "^6.26.0",
3030
"clean-webpack-plugin": "^3.0.0",
31+
"csv": "^5.5.0",
3132
"esbuild-loader": "^2.9.1",
3233
"gpu.js": "^2.9.5",
3334
"mathjs": "^7.1.0",
3435
"nerdamer": "^1.1.5",
36+
"sync-fetch": "^0.3.0",
3537
"webpack": "^5.21.2",
36-
"webpack-cli": "^4.5.0",
37-
"sync-fetch": "^0.3.0"
38+
"webpack-cli": "^4.5.0"
3839
},
3940
"devDependencies": {
4041
"@babel/types": "^7.10.5",

packages/hedgehog-core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ import { executeOutput } from './runtime';
22
import transpile from './transpiler/transpiler-core';
33

44
export * from './output/output-item';
5+
export * from './lib/table';
56

67
export { executeOutput, transpile };

packages/hedgehog-core/src/lib/mathlib.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Mat } from './matrix';
22

3-
function to_matrix(A: Mat | number[][] | number[] | number): Mat {
3+
function to_matrix(A: Mat | number[][] | number[] | number): Mat {
44
if (A instanceof Mat) {
55
return A.clone();
66
}

packages/hedgehog-core/src/lib/matrix.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ export class Mat {
602602
let ret = 0;
603603
for (let i = 0; i < this.rows; i++) {
604604
for (let j = 0; j < this.cols; j++) {
605-
let val = this.val[i][j];
605+
const val = this.val[i][j];
606606
ret += val * val;
607607
}
608608
}

packages/hedgehog-core/src/lib/random.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
Table is the data tructure that's designed for tabular data
3+
such as CSV file or matrix in CSV format as data frame
4+
*/
5+
6+
import * as csv from 'csv/lib/sync';
7+
8+
export class Table {
9+
// 2D string contains the table cells
10+
cells: string[][];
11+
12+
// row number
13+
rows: number;
14+
15+
// column number
16+
cols: number;
17+
18+
// array of string that contains header cells
19+
headers: string[];
20+
21+
// containsHeaders is true if this table contains headers
22+
containsHeaders: boolean;
23+
24+
/* The constructor contains three parameters:
25+
1. input a. raw csv string or b. 2-D string array as the raw data
26+
2. boolean header? if it contains headers
27+
*/
28+
constructor(input?: string | string[][] | Table, header?: boolean) {
29+
if (header === undefined) {
30+
this.containsHeaders = false;
31+
} else {
32+
this.containsHeaders = header;
33+
}
34+
this.cells = new Array(0);
35+
this.rows = 0;
36+
this.cols = 0;
37+
this.headers = new Array(0);
38+
if (typeof input === 'string') {
39+
const records = (csv.parse as any)(input, {
40+
columns: false,
41+
skip_empty_lines: true,
42+
quote: '"',
43+
ltrim: true,
44+
rtrim: true,
45+
delimiter: ','
46+
});
47+
this.cells = records;
48+
this.rows = records.length;
49+
this.cols = this.rows === 0 ? 0 : records[0].length;
50+
} else if (input instanceof Array) {
51+
this.cells = input;
52+
this.rows = input.length;
53+
this.cols = this.rows === 0 ? 0 : input[0].length;
54+
this.headers = new Array(0);
55+
}
56+
57+
// craete headers if it exists
58+
if (this.containsHeaders === true) {
59+
// fetch the first array in cells into headers
60+
if (this.cells.length > 1) {
61+
this.headers = this.cells[0];
62+
const newCells: string[][] = [];
63+
for (let idx = 1; idx < this.cells.length; idx++) {
64+
newCells.push(this.cells[idx]);
65+
}
66+
this.cells = newCells;
67+
} else {
68+
throw 'If "containsHeaders" is set as true, the table must contains at least one row.';
69+
}
70+
}
71+
}
72+
73+
/**
74+
* Insert a new row (array of string) at the end of table.
75+
*/
76+
insert(newTuple: string[]) {
77+
if (newTuple.length === this.cols) {
78+
this.cells.push(newTuple);
79+
} else {
80+
throw (
81+
'The length of new tuple inserting to the table is ' +
82+
newTuple.length +
83+
' but the columns of table is ' +
84+
this.cols +
85+
'. Please make sure that they are with the same length.'
86+
);
87+
}
88+
}
89+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// The class for tensor, n-dimensional array
2+
3+
export class Tensor {
4+
// val is an n-d array
5+
val: any[];
6+
// ndim is the number of dimensions.
7+
ndim: number;
8+
// shape is the array of number that contains the length of each dimension
9+
shape: number[];
10+
11+
//constructor of tensor classes
12+
constructor(input?: any[] | number) {
13+
this.val = [];
14+
this.ndim = 0;
15+
this.shape = [];
16+
if (typeof input === 'number') {
17+
this.val = [input];
18+
} else if (input !== undefined) {
19+
this.val = input;
20+
}
21+
this.initializeDimensions();
22+
}
23+
24+
/* initializeDimensions() function will check:
25+
1. The length of each dimension;
26+
2. Initialize the shape[] array of current tensor
27+
*/
28+
initializeDimensions(){
29+
let result:number[] = [];
30+
let currentDimensionPt = 0;
31+
let pt = this.val;
32+
while (pt instanceof Array) {
33+
currentDimensionPt += 1;
34+
result.push(pt.length);
35+
pt = pt[0];
36+
}
37+
this.shape = result;
38+
this.ndim = result.length;
39+
}
40+
41+
// return the list of each dimension
42+
dimensions(): number[] {
43+
return this.shape;
44+
}
45+
46+
/* return the string of this tensor in which each 2D array is
47+
formatted as a 2D matrix
48+
for example:
49+
[[[...],
50+
[...]],
51+
...
52+
]
53+
*/
54+
toString(): string {
55+
return JSON.stringify(this.val).split('],').join('],\n').split(']],').join(']],\n');
56+
}
57+
58+
/* return the string of this tensor in matrix format,
59+
which looks like the stringify 2D array
60+
for example: [[[...],[...]],[[...],[...]]]
61+
*/
62+
toStringDenseMode(): string {
63+
return JSON.stringify(this.val);
64+
}
65+
66+
log(): Tensor {
67+
console.log(this);
68+
return this;
69+
}
70+
71+
/*
72+
Deep clone current tensor into another Tensor object
73+
Todo: implement a more efficient way to clone
74+
*/
75+
clone() : Tensor {
76+
return JSON.parse(JSON.stringify(this))
77+
}
78+
79+
// Deep copy tensor A into this object
80+
copy(A:Tensor) : Tensor {
81+
const result = A.clone()
82+
this.val = result.val;
83+
this.ndim = result.ndim;
84+
this.shape = result.shape;
85+
return this;
86+
}
87+
88+
// TODO: Initialize a zero tensor in "shape"
89+
zerosAsShape(shape: number[]) : Tensor {
90+
let returnTensor = new Tensor();
91+
let currentSubTensor = [];
92+
return returnTensor;
93+
}
94+
95+
/*
96+
Todo: zeros function
97+
*/
98+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
99+
zeros(a0?:number,a1?:number,a2?:number,a3?:number,a4?:number,a5?:number,a6?:number,a7?:number,a8?:number,a9?:number,a10?:number,a11?:number,a12?:number,a13?:number,a14?:number,a15?:number) : Tensor {
100+
let returnTensor = new Tensor();
101+
let shape:number[] = [];
102+
for (let i=0;i<16;i++){
103+
// eslint-disable-next-line prefer-rest-params
104+
if (arguments[i] !== undefined) {
105+
if (arguments[i] === 0) {
106+
throw 'The dimension of the initialized zeros tensor cannot be zero.';
107+
}
108+
// eslint-disable-next-line prefer-rest-params
109+
shape.push(arguments[i]);
110+
}
111+
}
112+
return returnTensor;
113+
}
114+
115+
/*
116+
Todo list:
117+
1. Constructor for certain types of tensor, such as ones, random
118+
2. Operators for tensors
119+
3. GPU operators for tensors
120+
*/
121+
122+
}
123+
124+
export function tensor2json(A: Tensor): string {
125+
return JSON.stringify(A);
126+
}
127+
128+
export function json2tensor(json_str: string): Tensor {
129+
const obj = JSON.parse(json_str);
130+
return new Tensor(obj.val);
131+
}

packages/hedgehog-core/src/output/output-item.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// or a tuple of data and layout (into a figure of plotlyjs)
55
// and type is a string of "TEXT" or "DRAWING" or "TEX" or "FORMULA"
66

7+
import { Table } from '../lib/table';
8+
79
export type TextItem = {
810
itemType: 'TEXT';
911
text: string;
@@ -19,6 +21,15 @@ export type DrawingItem = {
1921
layout: any;
2022
};
2123

24+
export type TableItem = {
25+
itemType: 'TABLE';
26+
table: Table;
27+
};
28+
29+
export const isTableItem = (item: OutputItem) : item is TableItem => {
30+
return item.itemType === 'TABLE';
31+
};
32+
2233
export const isDrawingItem = (item: OutputItem): item is DrawingItem => {
2334
return item.itemType === 'DRAWING';
2435
};
@@ -50,4 +61,6 @@ export const isMarkdownItem = (item: OutputItem): item is MarkdownItem => {
5061
return item.itemType === 'MARKDOWN';
5162
};
5263

53-
export type OutputItem = TextItem | DrawingItem | TeXItem | FormulaItem | MarkdownItem;
64+
export type OutputItem = TextItem | DrawingItem | TeXItem | FormulaItem | MarkdownItem | TableItem;
65+
66+

packages/hedgehog-core/src/runtime/index.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,13 @@ export function executeOutput(code: string) {
1414
}
1515

1616
// eslint-disable-next-line no-new-func
17-
const fn = new Function(
18-
'prelude',
19-
preludeImport + code + '\n return _OUTPUT_ITEMS_LIST_;'
20-
);
17+
const fn = new Function('prelude', preludeImport + code + '\n return _OUTPUT_ITEMS_LIST_;');
2118

2219
const results = fn.call({}, prelude);
2320

24-
console.log('Execution results:');
21+
console.log('***Execution results***');
2522
console.log(results);
26-
console.log('-- End of execution results:');
23+
console.log('***End of execution results***');
2724

2825
const returnList = [...results];
2926
prelude._OUTPUT_ITEMS_LIST_.length = 0;

0 commit comments

Comments
 (0)