initial commit

backup-1
Antonio De Lucreziis 2 years ago
commit be437c2858

15
.gitignore vendored

@ -0,0 +1,15 @@
# Local files
.env
*.local*
# NodeJS
node_modules/
# Binaries
bin/
.out/
out/
dist/
# Editors
.vscode/

@ -0,0 +1,5 @@
# frozen_string_literal: true
source "https://rubygems.org"
# gem "rails"

@ -0,0 +1,12 @@
GEM
remote: https://rubygems.org/
specs:
PLATFORMS
ruby
x86_64-linux
DEPENDENCIES
BUNDLED WITH
2.5.17

@ -0,0 +1,50 @@
# Ricerca Operativa
Un piccolo sito con alcuni degli algoritmi presentati nel corso di Ricerca Operativa. Gli algoritmi sono scritti in Ruby e
eseguiti nel browser con WASM (uso il Ruby perché è l'unico linguaggio con i numeri razionali e buon supporto per WASM).
## Algoritmi
### Programmazione Lineare
- [ ] Metodo del simplesso
- [ ] Metodo del simplesso (con i conti)
- [ ] Metodo del simplesso (con disegnini)
- [ ] Metodo del simplesso duale
- [ ] Metodo del simplesso duale (con i conti)
- [ ] Metodo del simplesso duale (con disegnini)
### Programmazione Lineare Intera
- [ ] Branch and Bound
- [ ] Branch and Cut
- [ ] Branch and Price
### Programmazione Dinamica
- [ ] Algoritmo di Bellman
- [ ] Algoritmo di Dijkstra
- [ ] Algoritmo di Floyd
### Altri
- [ ] Algoritmo di Kruskal
## Usage
```bash
bun install
```
```bash
bun run index.ts
```

Binary file not shown.

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta property="og:title" content="Visualizzazioni di Ricerca Operativa" />
<meta property="og:description" content="Visualizzazioni di Ricerca Operativa" />
<meta property="og:type" content="website" />
<title>Visualizzazioni di Ricerca Operativa</title>
</head>
<body>
<script type="module" src="./src/main.jsx"></script>
</body>
</html>

@ -0,0 +1,27 @@
{
"name": "ricerca-operativa",
"module": "index.ts",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"@preact/preset-vite": "^2.9.0",
"@types/bun": "latest",
"@types/katex": "^0.16.7",
"@types/lodash": "^4.17.7",
"vite": "^5.4.1"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"dependencies": {
"@fontsource/inter": "^5.0.20",
"@ruby/3.3-wasm-wasi": "^2.6.2",
"@ruby/wasm-wasi": "^2.6.2",
"katex": "^0.16.11",
"lodash": "^4.17.21",
"vite-plugin-wasm": "^3.3.0"
}
}

@ -0,0 +1,29 @@
import { Steps } from '../../components/Steps.jsx'
import { evalRuby } from '../../ruby.js'
import algorithmCode from './algorithm.rb?raw'
import { useEffect, useState } from 'preact/hooks'
export const metadata = {
group: 'Programmazione Lineare',
title: 'Simplesso Primale Algebrico',
description: 'Algoritmo principale della programmazione lineare',
}
export const View = ({}) => {
const [steps, setSteps] = useState([])
useEffect(async () => {
const { outputs } = await evalRuby(algorithmCode)
setSteps(outputs)
}, [])
return (
<>
<h1>Simplesso Primale Algebrico</h1>
<p>TODO</p>
<Steps steps={steps} />
</>
)
}

@ -0,0 +1,30 @@
require "json"
require "js"
def print_step(label, state)
puts "Ruby: #{label} #{state}"
JS.global[:rubyOutputs].push({
label: label,
state: state
})
end
def run(config)
i = config["i"] || 1
j = config["j"] || 1
n = config["n"] || 10
print_step "Initial", { i: i, j: j, n: n }
n.times do
m = i + j
i = j
j = m
print_step "Step", { i: i, j: j }
end
return i
end
run({ "n" => 10 })

@ -0,0 +1,16 @@
import 'katex/dist/katex.min.css'
import katex from 'katex'
export const KaTeX = ({ source }) => {
console.log(source)
return (
<div
class="katex"
ref={el => {
if (!el) return
katex.render(source.toString(), el, { throwOnError: false })
}}
></div>
)
}

@ -0,0 +1,18 @@
import { KaTeX } from './KaTeX.jsx'
export const Steps = ({ steps }) => {
return (
<div class="steps">
{steps.map((step, i) => (
<div class="step">
<div class="label">{step.label}</div>
<div class="state">
{Object.entries(step.state).map(([key, value]) => (
<KaTeX source={`${key} = ${value}`} />
))}
</div>
</div>
))}
</div>
)
}

@ -0,0 +1,105 @@
import './style.css'
import '@fontsource/inter/latin.css'
import _ from 'lodash'
import { render } from 'preact'
import { useState } from 'preact/hooks'
const ViewRegistry = Object.fromEntries(
Object.entries(
import.meta.glob('./algorithms/*/View.jsx', {
eager: true,
})
/* fix for broken syntax highlighting */
).map(([path, module]) => {
const [id] = path.match(/(?<=\/)[^/]*(?=\/View\.jsx$)/)
return [id, { id, ...module }]
})
)
const NewAlgorithmBox = ({ title, description, onClick }) => (
<div class="algorithm-box" onClick={onClick}>
<h3>{title}</h3>
<p>{description}</p>
</div>
)
const AlgorithmChooserView = ({ setCurrentView }) => {
const sections = _.groupBy(ViewRegistry, 'metadata.group')
return (
<>
<h1>Algoritmi</h1>
{Object.entries(sections).map(([group, algorithms]) => (
<section>
<h2>{group}</h2>
<div class="boxes">
{algorithms.map(({ id, metadata }) => (
<NewAlgorithmBox
title={metadata.title}
description={metadata.description}
onClick={() => setCurrentView(id)}
/>
))}
</div>
</section>
))}
<section>
<h2>Flussi su Grafi</h2>
<div class="boxes">
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
</div>
</section>
<section>
<h2>Flussi su Grafi</h2>
<div class="boxes">
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
</div>
</section>
<section>
<h2>Flussi su Grafi</h2>
<div class="boxes">
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
<NewAlgorithmBox title="TODO" description="lorem ipsum dolor sit amet" />
</div>
</section>
</>
)
}
const Main = ({}) => {
const [currentView, setCurrentView] = useState(null)
if (!currentView) {
return <AlgorithmChooserView setCurrentView={setCurrentView} />
}
const View = ViewRegistry[currentView].View
return <View />
}
const App = ({}) => {
return (
<>
<header>Visualizzazioni di Ricerca Operativa</header>
<aside>
<h2>History</h2>
</aside>
<main>
<Main />
</main>
</>
)
}
render(<App />, document.body)

@ -0,0 +1,26 @@
import rubyWasmModuleUrl from '@ruby/3.3-wasm-wasi/dist/ruby+stdlib.wasm?url'
import { DefaultRubyVM } from '@ruby/wasm-wasi/dist/browser'
window.rubyOutputs = []
let vmInstance = null
async function preloadRuby() {
if (vmInstance) return
const response = await fetch(rubyWasmModuleUrl)
const module = await WebAssembly.compileStreaming(response)
const { vm } = await DefaultRubyVM(module)
vmInstance = vm
}
export async function evalRuby(code) {
await preloadRuby()
window.rubyOutputs = []
const result = vmInstance.eval(code)
return {
result,
outputs: window.rubyOutputs,
}
}

@ -0,0 +1,176 @@
*,
*::before,
*::after {
font-family: inherit;
padding: 0;
margin: 0;
box-sizing: border-box;
}
html,
body {
min-height: 100%;
height: 100%;
}
body {
width: 100vw;
height: 100vh;
position: fixed;
overflow: hidden;
user-select: none;
}
img {
display: block;
}
/* Typography */
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Inter', sans-serif;
font-weight: 500;
}
/* Components */
.boxes {
display: flex;
flex-direction: row;
gap: 1rem;
align-items: start;
.algorithm-box {
display: grid;
grid-template-rows: auto 1fr;
gap: 0.25rem;
padding: 1rem;
border-radius: 0.75rem;
background: #fff;
border: 2px solid #333;
width: 10rem;
min-height: calc(10rem * 3 / 4);
p {
color: #444;
}
cursor: pointer;
&:hover {
background: #f4f4f4;
}
}
}
.steps {
display: grid;
grid-template-columns: 1fr;
place-self: center;
gap: 1rem;
.step {
display: grid;
grid-template-rows: auto 1fr;
gap: 0.5rem;
padding: 1rem;
border-radius: 0.75rem;
background: #fff;
border: 2px solid #333;
min-width: 20rem;
& > .label {
font-weight: 500;
font-size: 15px;
}
& > .state {
display: grid;
grid-template-columns: 1fr;
gap: 0.25rem;
}
}
}
/* Structure */
body {
display: grid;
grid-template-columns: 20% 1fr;
grid-template-rows: auto 1fr;
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 16px;
background: #f0f0f0;
& > header,
aside,
main,
footer {
display: grid;
place-content: center;
padding: 0 1rem;
}
& > header {
height: 3rem;
grid-column: span 2;
border-bottom: 2px solid #333;
background: #fff;
font-weight: 300;
font-size: 1.25rem;
}
& > aside {
border-right: 2px solid #333;
background: #e0e0e0;
position: sticky;
height: 100vh;
padding: 1rem;
align-content: start;
}
& > main {
display: grid;
grid-template-columns: auto;
padding: 6rem 1rem;
gap: 1.5rem;
place-content: center;
align-content: start;
overflow: auto;
& > section {
display: grid;
grid-template-columns: auto;
gap: 0.5rem;
}
}
}

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

@ -0,0 +1,15 @@
import { defineConfig } from 'vite'
import wasm from 'vite-plugin-wasm'
import preactPlugin from '@preact/preset-vite'
export default defineConfig({
build: {
outDir: 'out',
emptyOutDir: true,
},
server: {
port: 3000,
},
plugins: [preactPlugin(), wasm()],
})
Loading…
Cancel
Save