testing workflows (#14) - DO NOT MERGE #33
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": ["next/core-web-vitals", "next/typescript"],
|
||||||
|
"rules": {
|
||||||
|
"react/no-unescaped-entities": "off",
|
||||||
|
"@next/next/no-page-custom-font": "off",
|
||||||
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
|
"prefer-const": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
name: Run Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
workflow_dispatch:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: npm test
|
||||||
+36
@@ -847,3 +847,39 @@ FodyWeavers.xsd
|
|||||||
|
|
||||||
### VisualStudio Patch ###
|
### VisualStudio Patch ###
|
||||||
# Additional files built by Visual Studio
|
# Additional files built by Visual Studio
|
||||||
|
|
||||||
|
### Added by npx/npm for Next.JS ###
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.js
|
||||||
|
.yarn/install-state.gz
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env*.local
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
|
||||||
|
export default function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
res.status(200).json({ message: 'API is working!' });
|
||||||
|
} else {
|
||||||
|
res.status(405).json({ message: 'Method not allowed' });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/** @type {import('jest').Config} */
|
||||||
|
const nextJest = require('next/jest');
|
||||||
|
|
||||||
|
const createJestConfig = nextJest({
|
||||||
|
dir: './',
|
||||||
|
});
|
||||||
|
|
||||||
|
const customJestConfig = {
|
||||||
|
testEnvironment: 'jsdom',
|
||||||
|
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
|
||||||
|
moduleNameMapper: {
|
||||||
|
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(ts|tsx)$': 'ts-jest',
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = createJestConfig(customJestConfig);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import '@testing-library/jest-dom';
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
/**
|
||||||
|
* Enable static exports for the App Router.
|
||||||
|
*
|
||||||
|
* @see https://nextjs.org/docs/app/building-your-application/deploying/static-exports
|
||||||
|
*/
|
||||||
|
output: "export",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set base path. This is the slug of your GitHub repository.
|
||||||
|
*
|
||||||
|
* @see https://nextjs.org/docs/app/api-reference/next-config-js/basePath
|
||||||
|
*/
|
||||||
|
basePath: "/nextjs-github-pages",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable server-based image optimization. Next.js does not support
|
||||||
|
* dynamic features with static exports.
|
||||||
|
*
|
||||||
|
* @see https://nextjs.org/docs/app/api-reference/components/image#unoptimized
|
||||||
|
*/
|
||||||
|
images: {
|
||||||
|
unoptimized: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
Generated
+9996
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "or-tool",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"next": "14.2.11",
|
||||||
|
"react": "^18",
|
||||||
|
"react-dom": "^18",
|
||||||
|
"reactjs-popup": "^2.0.6"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@testing-library/jest-dom": "^6.5.0",
|
||||||
|
"@testing-library/react": "^16.0.1",
|
||||||
|
"@testing-library/user-event": "^14.5.2",
|
||||||
|
"@types/jest": "^29.5.13",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^18",
|
||||||
|
"@types/react-dom": "^18",
|
||||||
|
"eslint": "^8",
|
||||||
|
"eslint-config-next": "14.2.11",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
|
"postcss": "^8",
|
||||||
|
"tailwindcss": "^3.4.1",
|
||||||
|
"ts-jest": "^29.2.5",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/** @type {import('postcss-load-config').Config} */
|
||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,153 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--background: #ffffff;
|
||||||
|
--foreground: #171717;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--background: #0a0a0a;
|
||||||
|
--foreground: #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: var(--foreground);
|
||||||
|
background: var(--background);
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.text-balance {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-size: 36px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header_box {
|
||||||
|
flex: 1;
|
||||||
|
margin: 10px 10px;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 20px solid #202020;
|
||||||
|
background-color: #202020;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header_copyright {
|
||||||
|
font-size: 16px;
|
||||||
|
color:#707070;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
border: 2px solid #5353535c;
|
||||||
|
background-color: #1010105c;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
border: 2px solid #5353535c;
|
||||||
|
background-color: #5353535c;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button_green {
|
||||||
|
border: 2px solid #4795475c;
|
||||||
|
background-color: #247d245c;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button_red {
|
||||||
|
border: 2px solid #9547475c;
|
||||||
|
background-color: #7d24245c;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button_green:hover {
|
||||||
|
border: 2px solid #4795475c;
|
||||||
|
background-color: #4795475c;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button_red:hover {
|
||||||
|
border: 2px solid #9547475c;
|
||||||
|
background-color: #9547475c;
|
||||||
|
border-radius: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main_div {
|
||||||
|
flex: 1;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body_box {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #8d8d8d;
|
||||||
|
background-color: #474747;
|
||||||
|
font-size: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body_title {
|
||||||
|
font-size: 20px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output_box {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 2px solid #8d8d8d;
|
||||||
|
background-color: #4dc3435c;
|
||||||
|
font-size: 10;
|
||||||
|
height: fit-content 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup_bg {
|
||||||
|
width: 2000px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 10px #7c7c7c;
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-overlay {
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Image from "next/image";
|
||||||
|
import localFont from "next/font/local";
|
||||||
|
import "./globals.css";
|
||||||
|
|
||||||
|
const geistSans = localFont({
|
||||||
|
src: "./fonts/GeistVF.woff",
|
||||||
|
variable: "--font-geist-sans",
|
||||||
|
weight: "100 900",
|
||||||
|
});
|
||||||
|
const geistMono = localFont({
|
||||||
|
src: "./fonts/GeistMonoVF.woff",
|
||||||
|
variable: "--font-geist-mono",
|
||||||
|
weight: "100 900",
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Create Next App",
|
||||||
|
description: "Generated by create next app",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body
|
||||||
|
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
||||||
|
<footer className=" flex gap-6 flex-wrap items-center justify-center">
|
||||||
|
<a
|
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
|
href="https://github.com/Spaceholder-Programming/Operations-Research-Tool/wiki"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
aria-hidden
|
||||||
|
src="https://nextjs.org/icons/file.svg"
|
||||||
|
alt="File icon"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
Go to our docs
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
|
href="https://github.com/Spaceholder-Programming/Operations-Research-Tool/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
aria-hidden
|
||||||
|
src="https://nextjs.org/icons/globe.svg"
|
||||||
|
alt="Globe icon"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
See the source code
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||||
|
href="https://www.gnu.org/software/glpk/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
aria-hidden
|
||||||
|
src="https://nextjs.org/icons/globe.svg"
|
||||||
|
alt="Globe icon"
|
||||||
|
width={16}
|
||||||
|
height={16}
|
||||||
|
/>
|
||||||
|
Powered by GLPK
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { MouseEventHandler } from "react";
|
||||||
|
import Popup from "reactjs-popup";
|
||||||
|
|
||||||
|
export function Box({title, placeholder, id}:
|
||||||
|
{title:string; placeholder:string; id:string}) {
|
||||||
|
return(
|
||||||
|
<div className="main_div">
|
||||||
|
<div className="body_title">
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
<div className="text">
|
||||||
|
<textarea
|
||||||
|
className="body_box"
|
||||||
|
id={id}
|
||||||
|
wrap="soft"
|
||||||
|
rows={6}
|
||||||
|
placeholder={placeholder}
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Button({title, className, onClickFunc}:
|
||||||
|
{title:string; className:string|undefined; onClickFunc: MouseEventHandler}) {
|
||||||
|
|
||||||
|
return(
|
||||||
|
<button
|
||||||
|
className={className}
|
||||||
|
onClick={onClickFunc}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Popup_Button({title, className}:
|
||||||
|
{title:string; className:string|undefined;}) {
|
||||||
|
|
||||||
|
return(
|
||||||
|
<Popup
|
||||||
|
trigger={<button
|
||||||
|
className={className}>
|
||||||
|
{title}
|
||||||
|
</button>}
|
||||||
|
position="right center"
|
||||||
|
modal
|
||||||
|
nested>
|
||||||
|
{close => (
|
||||||
|
<div className="popup_bg">
|
||||||
|
<button onClick={close}>
|
||||||
|
×
|
||||||
|
</button>
|
||||||
|
<div className="header"> {title} </div>
|
||||||
|
<div className="content">
|
||||||
|
This is a popup example.
|
||||||
|
</div>
|
||||||
|
<div className="actions">
|
||||||
|
<button className="button" onClick={close}>
|
||||||
|
Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Popup>
|
||||||
|
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Output({id, text}:
|
||||||
|
{id:string; text:string}) {
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="main_div">
|
||||||
|
<div className="body_title"
|
||||||
|
>
|
||||||
|
Output
|
||||||
|
</div>
|
||||||
|
<div className="text">
|
||||||
|
<p
|
||||||
|
className="output_box"
|
||||||
|
id={id}
|
||||||
|
value={text}>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Box, Button, Output, Popup_Button } from "./modules.tsx";
|
||||||
|
import { calculate_click, import_click, export_click } from "./scripts.ts"
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header className="header">
|
||||||
|
<div className="title">
|
||||||
|
<main className="header_box">
|
||||||
|
Operations Research Tool
|
||||||
|
<br></br>
|
||||||
|
<span className="header_copyright">
|
||||||
|
<i>by Spaceholder Programming</i>
|
||||||
|
</span>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<Box
|
||||||
|
title={"Functions"}
|
||||||
|
placeholder={"Your Functions here"}
|
||||||
|
id="funcs"/>
|
||||||
|
<Box
|
||||||
|
title={"Variables"}
|
||||||
|
placeholder={"Your Variables here"}
|
||||||
|
id="vars" />
|
||||||
|
<Button
|
||||||
|
title={"Calculate"}
|
||||||
|
className={"button_green"}
|
||||||
|
onClickFunc={calculate_click} />
|
||||||
|
<Popup_Button
|
||||||
|
title={"Import"}
|
||||||
|
className={"button"} />
|
||||||
|
<Popup_Button
|
||||||
|
title={"Export"}
|
||||||
|
className={"button"} />
|
||||||
|
<br></br>
|
||||||
|
<Output
|
||||||
|
id="out"
|
||||||
|
text={"Ergebnis"}/>
|
||||||
|
<Popup_Button
|
||||||
|
title="Popup"
|
||||||
|
className="button"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
export function test() {
|
||||||
|
console.log("Dies ist die Testfunktion.");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function calculate_click() {
|
||||||
|
console.log("Calculating...");
|
||||||
|
|
||||||
|
let functions:string = document.getElementById('funcs').value;
|
||||||
|
let variables:string = document.getElementById('vars').value;
|
||||||
|
|
||||||
|
let funcs:string[] = functions.split(/; */);
|
||||||
|
let vars:string[] = variables.split(/; */);
|
||||||
|
|
||||||
|
|
||||||
|
// Irgend ein Interface
|
||||||
|
// document.getElementById('out').innerHTML = funcs;
|
||||||
|
|
||||||
|
// output.innerHTML = functions.innerHTML;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function import_click() {
|
||||||
|
console.log("Importing...");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function export_click() {
|
||||||
|
console.log("Exporting...");
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import GLPK from 'glpk.js';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
const { objective, constraints } = req.body;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const glpk = await GLPK();
|
||||||
|
const options = {
|
||||||
|
msglev: glpk.GLP_MSG_ALL,
|
||||||
|
presol: true,
|
||||||
|
cb: {
|
||||||
|
call: (progress: any) => console.log(progress),
|
||||||
|
each: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const problem = {
|
||||||
|
name: 'LP',
|
||||||
|
objective: {
|
||||||
|
direction: objective.direction === 'max' ? glpk.GLP_MAX : glpk.GLP_MIN,
|
||||||
|
name: 'obj',
|
||||||
|
vars: objective.vars
|
||||||
|
},
|
||||||
|
subjectTo: constraints.map((c: any) => ({
|
||||||
|
name: c.name,
|
||||||
|
vars: c.vars,
|
||||||
|
bnds: {
|
||||||
|
type: glpk.GLP_UP,
|
||||||
|
ub: c.bnds.ub,
|
||||||
|
lb: c.bnds.lb
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = glpk.solve(problem, options);
|
||||||
|
|
||||||
|
const lpFormat = `\n# Problem Definition\n
|
||||||
|
name: ${problem.name}\n
|
||||||
|
# Objective Function\n
|
||||||
|
${problem.objective.direction === glpk.GLP_MAX ? 'max' : 'min'} ${problem.objective.vars.map((v: any) => `${v.coef} ${v.name}`).join(' + ')}\n
|
||||||
|
# Constraints\n
|
||||||
|
${problem.subjectTo.map((c: any) => `${c.vars.map((v: any) => `${v.coef} ${v.name}`).join(' + ')} ${c.bnds.ub ? `<= ${c.bnds.ub}` : ''}`).join('\n')}\n`;
|
||||||
|
|
||||||
|
res.status(200).json({ result, lpFormat });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error processing optimization:', error);
|
||||||
|
res.status(500).json({ message: 'Error processing optimization', error: error.message });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(405).json({ message: 'Only POST method is allowed' });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import GLPK from 'glpk.js';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
const { objective, constraints, bounds } = req.body;
|
||||||
|
|
||||||
|
if (!objective || !constraints) {
|
||||||
|
return res.status(400).json({ message: 'Invalid input data. Ensure that "objective" and "constraints" are provided correctly.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const glpk = await GLPK();
|
||||||
|
const options = { msglev: glpk.GLP_MSG_ALL, presol: true };
|
||||||
|
|
||||||
|
const problem = {
|
||||||
|
name: 'MIP',
|
||||||
|
objective: {
|
||||||
|
direction: objective.direction === 'max' ? glpk.GLP_MAX : glpk.GLP_MIN,
|
||||||
|
name: 'obj',
|
||||||
|
vars: objective.vars.map(v => ({ name: v.name, coef: v.coef }))
|
||||||
|
},
|
||||||
|
subjectTo: constraints.map(c => ({
|
||||||
|
name: c.name,
|
||||||
|
vars: c.vars.map(v => ({ name: v.name, coef: v.coef })),
|
||||||
|
bnds: {
|
||||||
|
type: glpk.GLP_UP,
|
||||||
|
lb: c.bnds.lb,
|
||||||
|
ub: c.bnds.ub
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
binaries: objective.vars.map(v => v.name),
|
||||||
|
generals: objective.vars.map(v => v.name)
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = glpk.solve(problem, options);
|
||||||
|
res.status(200).json({ result });
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ message: 'Error processing optimization', error: error.message });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(405).json({ message: 'Only POST method is allowed' });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
type VariableLP = { name: string; coef: number };
|
||||||
|
type ConstraintLP = {
|
||||||
|
name: string;
|
||||||
|
vars: VariableLP[];
|
||||||
|
bnds: { ub: number; lb: number };
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ProblemLP {
|
||||||
|
objective: {
|
||||||
|
vars: VariableLP[];
|
||||||
|
};
|
||||||
|
constraints: ConstraintLP[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createProblemLP(
|
||||||
|
objectiveVars: VariableLP[],
|
||||||
|
constraints: { name: string; vars: VariableLP[]; ub: number; lb: number }[]
|
||||||
|
): ProblemLP {
|
||||||
|
const constraintsFormatted: ConstraintLP[] = constraints.map((constraint) => ({
|
||||||
|
name: constraint.name,
|
||||||
|
vars: constraint.vars,
|
||||||
|
bnds: {
|
||||||
|
ub: constraint.ub,
|
||||||
|
lb: constraint.lb
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const problem: ProblemLP = {
|
||||||
|
objective: {
|
||||||
|
vars: objectiveVars
|
||||||
|
},
|
||||||
|
constraints: constraintsFormatted
|
||||||
|
};
|
||||||
|
|
||||||
|
return problem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
interface VariableMIP {
|
||||||
|
name: string;
|
||||||
|
coef: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Bounds {
|
||||||
|
type: number;
|
||||||
|
ub: number;
|
||||||
|
lb: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ConstraintMIP {
|
||||||
|
name: string;
|
||||||
|
vars: VariableMIP[];
|
||||||
|
bnds: Bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
mipgap: number;
|
||||||
|
tmlim: number;
|
||||||
|
msglev: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Problem {
|
||||||
|
name: string;
|
||||||
|
objective: {
|
||||||
|
direction: "min" | "max";
|
||||||
|
name: string;
|
||||||
|
vars: VariableMIP[];
|
||||||
|
};
|
||||||
|
constraints: ConstraintMIP[];
|
||||||
|
binaries?: string[];
|
||||||
|
generals?: string[];
|
||||||
|
options: Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createProblemMIP(
|
||||||
|
name: string,
|
||||||
|
direction: "min" | "max",
|
||||||
|
objectiveName: string,
|
||||||
|
objectiveVars: VariableMIP[],
|
||||||
|
constraints: { name: string; vars: VariableMIP[]; bnds_type: number; ub: number; lb: number }[],
|
||||||
|
binaries: string[],
|
||||||
|
generals: string[] = [],
|
||||||
|
mipgap: number,
|
||||||
|
tmlim: number,
|
||||||
|
msglev: number
|
||||||
|
): Problem {
|
||||||
|
const constraintsFormatted: ConstraintMIP[] = constraints.map((constraint) => ({
|
||||||
|
name: constraint.name,
|
||||||
|
vars: constraint.vars,
|
||||||
|
bnds: {
|
||||||
|
type: constraint.bnds_type,
|
||||||
|
ub: constraint.ub,
|
||||||
|
lb: constraint.lb
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const problem: Problem = {
|
||||||
|
name: name,
|
||||||
|
objective: {
|
||||||
|
direction: direction,
|
||||||
|
name: objectiveName,
|
||||||
|
vars: objectiveVars
|
||||||
|
},
|
||||||
|
constraints: constraintsFormatted,
|
||||||
|
binaries: binaries.length > 0 ? binaries : undefined,
|
||||||
|
generals: generals.length > 0 ? generals : undefined,
|
||||||
|
options: {
|
||||||
|
mipgap: mipgap,
|
||||||
|
tmlim: tmlim,
|
||||||
|
msglev: msglev
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return problem;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import type { Config } from "tailwindcss";
|
||||||
|
|
||||||
|
const config: Config = {
|
||||||
|
content: [
|
||||||
|
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||||
|
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||||
|
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
background: "var(--background)",
|
||||||
|
foreground: "var(--foreground)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user