Skip to content

Commit

Permalink
chore(data): more datasets and build settings
Browse files Browse the repository at this point in the history
  • Loading branch information
pandomic committed Nov 5, 2023
1 parent fee184f commit 6158bb4
Show file tree
Hide file tree
Showing 29 changed files with 246 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
.idea
.lock
.tmp
*.log
node_modules
build
Expand Down
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
cmake -DFAST_BUILD=ON -DBUILD_SHARED_LIBS=OFF ..
cmake --build .
build-highs:
mkdir -p .tmp && cd .tmp && \
git clone [email protected]:ERGO-Code/HiGHS.git && cd HiGHS && \
mkdir -p build && cd build && \
cmake -DFAST_BUILD=ON -DBUILD_SHARED_LIBS=ON ..;
cd .tmp/HiGHS/build && cmake --build .;

.PHONY: build-highs
67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,77 @@
# Rectengular Sets Visualisation

TODO: add more info
## About the Project

This project implements rectangular Euler-like sets visualization described in the following paper and its supplementary:
* [Paper](https://graphics.uni-konstanz.de/publikationen/Paetzold2023RectEulerVisualizingIntersecting/Rectangular_Euler_Diagrams_preprint.pdf)
* [Supplementary](https://graphics.uni-konstanz.de/publikationen/Paetzold2023RectEulerVisualizingIntersecting/Rectangular_Euler_Diagrams_supp.pdf)

### High-level Design

![](docs/design_diagram.png)

### Additional Performance Optimizations

* We use hash tables to minimize duplications when computing intersections, exclusions, or caching constraints. To make sure constraints only appear once, we use sorted hashes.
* Label overlapping will likely occur on intersections, therefore we only compute label constraints for intersecting sets
* Exclusion constraints are only computed for parent-most sets to avoid creating unnecessary constraints, as group exclusion from the parent set automatically means exclusion from all child nodes

### Performance Evaluation

Although the project uses a highly efficient LP Solver HiGHS, it cannot achieve the same performance levels as commercial products.

Performance of the application highly depends on the complexity of the dataset. Optimization may be taking from seconds up to tens of minutes for highly intersecting sets.

We therefore introduce constraint toggles, to let the user decide which constraints to compute. This allows the user to trade-off between performance and accuracy.

### Feature Overview

**Home Screen**

![](docs/home_screen.png)

**Preview Screen**

![](docs/preview_screen.png)

**Solution Screen**

![](docs/solution_screen.png)

## Setting Up Dev Environment

1. For simplicity, use [nodeenv](https://github.com/ekalinin/nodeenv) to manage node versions. Recommended version is >= 16
1. For simplicity, use [nvm](https://github.com/nvm-sh/nvm) to manage node versions. Recommended version is >= 18
2. Install yarn package manager: `npm install -g yarn`
3. Install project dependencies: `yarn install`
4. Run the project: `yarn start`

## Packaging the Project

To create project binaries simply run:

```bash
yarn package
```

You will find the binaries under the `build` folder.

## Adding new HiGHS binaries

At the moment the project offers two HiGHS binaries (can be found under `src/resources/binaries`):
1. `highs_darwin_arm64` for Apple Silicon (macOS)
2. `highs.wasm` - C++-based web assembly binary which is used as a fallback option

### Building a new HiGHS binary

> Note you will need `cmake` and `make` for the following steps
The actual platform-specific binary may be a little bit faster. You can therefore build and add a binary by yourself:
```bash
make build-highs
```

The binary (you will find it under `.tmp/HiGHS/build`) has to be placed under `src/resources/binaries` and added to the mapping in `src/models/solvers/highs.ts`.

### Testing and Developing components in isolation

```bash
Expand Down
Binary file added docs/design_diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/home_screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/preview_screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/solution_screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions electron-builder.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"appId": "org.rectangulator.app",
"productName": "Rectangulator",
"artifactName": "rectangulator-${env.BUILD_MODE}-${version}.${ext}",
"artifactName": "rectangulator-${version}.${ext}",
"copyright": "Anastasios Karampekios & Vlad Gramuzov",
"compression": "maximum",
"directories": {
Expand All @@ -20,5 +20,8 @@
"win": {
"icon": "dist/icon.ico",
"target": ["nsis", "appx"]
}
},
"extraResources": [
"./dist/binaries/*"
]
}
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "Proprietary",
"private": true,
"scripts": {
"package": "NODE_ENV=production electron-builder --publish never -c electron-builder.json",
"package": "NODE_ENV=production yarn build && electron-builder --publish never -c electron-builder.json",
"start": "concurrently -k \"node esbuild.js\" \"yarn electron .\"",
"build": "node esbuild.js",
"lint": "eslint --ext .ts src",
Expand All @@ -24,19 +24,19 @@
"esbuild": "^0.14.11",
"esbuild-plugin-copy": "^2.1.1",
"eslint": "^8.52.0",
"typescript": "^5.2.2"
"typescript": "^5.2.2",
"electron": "^27.0.2",
"electron-builder": "^24.6.4",
"electron-is-dev": "^2.0.0",
"@types/node": "^20.8.8",
"@types/react": "^18.2.31",
"@types/react-dom": "^18.2.14"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@fontsource/roboto": "^5.0.8",
"@mui/material": "^5.14.15",
"@types/node": "^20.8.8",
"@types/react": "^18.2.31",
"@types/react-dom": "^18.2.14",
"electron": "^27.0.2",
"electron-builder": "^24.6.4",
"electron-is-dev": "^2.0.0",
"highs": "^1.0.0",
"lodash": "^4.17.21",
"murmurhash-js": "^1.0.0",
Expand Down
Binary file added public/datasets/dataset_simpsons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/datasets/dataset_vitamins.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified public/favicon.ico
Binary file not shown.
Binary file added public/icon.icns
Binary file not shown.
Binary file added public/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/logo192.png
Binary file not shown.
Binary file removed public/logo512.png
Binary file not shown.
25 changes: 0 additions & 25 deletions public/manifest.json

This file was deleted.

26 changes: 24 additions & 2 deletions src/components/views/home.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ReactElement, useState } from 'react';
import { Grid } from '@mui/material';
import { Grid, Box, Button } from '@mui/material';

import {DataSetPreview, LPNewModel} from '@/types';
import { DataSetPreview, LPNewModel } from '@/types';
import { HomeLayout } from '@/components/layouts';
import { Dataset, DatasetPreview } from '@/components/elements';
import { DATASETS } from '@/datasets';
import { parseData, ParserType } from '@/data';

export interface HomeViewProps {
onSelectDataset?: (dataset: DataSetPreview, model: LPNewModel) => unknown;
Expand All @@ -13,6 +14,22 @@ export interface HomeViewProps {
export const HomeView = ({ onSelectDataset }: HomeViewProps): ReactElement => {
const [selectedDataset, setSelectedDataset] = useState<DataSetPreview | null>(null);

const handleSelectCustomDataset = async () => {
const content = await window.IPC.showCSVSelectionDialog();

if (!content) return;

const parsedDataset = parseData(content, ParserType.CSV);

const customDataset = {
name: 'Custom Dataset',
description: `A custom dataset with ${parsedDataset.labels.size} labels and ${parsedDataset.dataWithLabels.size} data points`,
...parsedDataset,
};

setSelectedDataset(customDataset);
};

return (
<HomeLayout>
<DatasetPreview
Expand All @@ -21,6 +38,11 @@ export const HomeView = ({ onSelectDataset }: HomeViewProps): ReactElement => {
onClose={() => setSelectedDataset(null)}
onConfirm={onSelectDataset}
/>
<Box>
<Button fullWidth variant="outlined" onClick={handleSelectCustomDataset}>
Upload a Dataset
</Button>
</Box>
<Grid container spacing={3} height="100%">
{DATASETS.map((dataset) => (
<Grid key={dataset.name} item xs={12} sm={6} md={3} lg={3} xl={4}>
Expand Down
57 changes: 35 additions & 22 deletions src/components/views/solution.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,24 @@ export const SolutionView = ({ model, dataset, onBack }: SolutionViewProps): Rea

const svgRef = useRef<SVGElement>(null);

useEffect(() => {
const computeSolution = async () => {
const startSeconds = new Date().getTime() / 1000;
const computedSolution = await window.IPC.optimizeMIPModel(model);
const endSeconds = new Date().getTime() / 1000;

if (computedSolution.Status !== 'Optimal') {
setError(true);
setComputing(false);
return;
}

const date = new Date(0);
date.setSeconds(endSeconds - startSeconds);

setTime(date.toISOString().substring(11, 19));
setSolution(computedSolution);
const computeSolution = async () => {
const startSeconds = new Date().getTime() / 1000;
const computedSolution = await window.IPC.optimizeMIPModel(model);
const endSeconds = new Date().getTime() / 1000;

if (computedSolution.Status !== 'Optimal') {
setError(true);
setComputing(false);
};
return;
}

computeSolution();
}, [model]);
const date = new Date(0);
date.setSeconds(endSeconds - startSeconds);

setTime(date.toISOString().substring(11, 19));
setSolution(computedSolution);
setComputing(false);
};

const classifiedDataset = useMemo(() => {
return classifyDataSet(groupDataSet(dataset));
Expand All @@ -68,6 +64,16 @@ export const SolutionView = ({ model, dataset, onBack }: SolutionViewProps): Rea
URL.revokeObjectURL(link.href);
};

const handleRetry = () => {
setError(false);
setComputing(true);
computeSolution();
};

useEffect(() => {
computeSolution();
}, [model]);

return (
<SolutionLayout
showToolbar={!computing && !error && !!solution}
Expand Down Expand Up @@ -96,12 +102,19 @@ export const SolutionView = ({ model, dataset, onBack }: SolutionViewProps): Rea
)}
{!computing && error && (
<Box width="100%" height="100%" display="flex" flexDirection="column">
<Alert severity="warning">
<Alert
severity="warning"
action={
<Button color="inherit" size="small" onClick={handleRetry}>
Retry
</Button>
}
>
We were unable to find an optimal solution for your problem.
Consider reducing the dataset size or splitting it into multiple parts.
</Alert>
<Box mt={2}>
<Button variant="outlined" size="large" fullWidth>
<Button variant="outlined" size="large" fullWidth onClick={onBack}>
Return to Home
</Button>
</Box>
Expand Down
4 changes: 3 additions & 1 deletion src/data/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ export enum ParserType {
export type ParserFunction = (data: string) => DataSet;

export const parseCsvData: ParserFunction = (data: string): DataSet => {
const lines = data.split("\n");
const adjustedData = data.replace(/\r/g, "");

const lines = adjustedData.split("\n");
const labels = lines[0].split(",");

const entities: [string, Set<string>][] = labels.map((label) => [label, new Set()]);
Expand Down
4 changes: 4 additions & 0 deletions src/datasets/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import potter from './potter';
import venn from './venn';
import simpsons from './simpsons';
import vitamins from './vitamins';

export const DATASETS = [
potter,
venn,
simpsons,
vitamins,
];
6 changes: 4 additions & 2 deletions src/datasets/potter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ Ms.Norris,Myrte,Wormtail,Remus,Ms.Norris,Draco,Hermione,Dumbledore,Dumbledore
,,,,Dudley,,,,Myrte
,,,,Vernon,,,,Grindelwald`;

const parsedData = parseData(CSV_DATA, ParserType.CSV);

const dataset: DataSetPreview = {
name: 'Harry Potter',
description: 'A dataset with 4 groups and 4 sets',
description: `A custom dataset with ${parsedData.labels.size} labels and ${parsedData.dataWithLabels.size} data points`,
image: 'datasets/dataset_potter.png',
...parseData(CSV_DATA, ParserType.CSV),
...parsedData,
};

export default dataset;
33 changes: 33 additions & 0 deletions src/datasets/simpsons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { parseData, ParserType } from '@/data';
import { DataSetPreview } from '@/types';

const CSV_DATA = `Male,Duff Fan,Power Plant,Evil,School,Blue Hair
Kent Brockman,Barney,Lenny Leonard,Krusty,Martin Prince,Milhouse
Grampa,Mo,Carl Carlson,Nelson,Bart,Marge
Ned,Krusty,Homer,Mr. Burns,Ralph,Jacqueline Bouvier
Barney,Lenny Leonard,,Smithers,Nelson,
Mo,Carl Carlson,,Sideshow Bob,Milhouse,
Martin Prince,Homer,,Fat Tony,Lisa,
Bart,,,,,
Ralph,,,,,
Krusty,,,,,
Nelson,,,,,
Milhouse,,,,,
Lenny Leonard,,,,,
Carl Carlson,,,,,
Homer,,,,,
Mr. Burns,,,,,
Smithers,,,,,
Sideshow Bob,,,,,
Fat Tony,,,,,`;

const parsedData = parseData(CSV_DATA, ParserType.CSV);

const dataset: DataSetPreview = {
name: 'Simpsons',
description: `A dataset with ${parsedData.labels.size} labels and ${parsedData.dataWithLabels.size} data points`,
image: 'datasets/dataset_simpsons.png',
...parsedData,
};

export default dataset;
Loading

0 comments on commit 6158bb4

Please sign in to comment.