Adding MPS Export #49

Merged
SinusFox merged 61 commits from adding-unit-tests-and-language-switching into main 2024-10-11 14:08:24 +00:00
2 changed files with 230 additions and 80 deletions
Showing only changes of commit e48f11d03a - Show all commits
+140 -8
View File
@@ -9,27 +9,93 @@ export default function text(lang: string, input: string): string {
case "boxObjTitle": case "boxObjTitle":
return "Ziel"; return "Ziel";
case "boxObjDesc": case "boxObjDesc":
return "Gib hier dein Ziel ein. Es ist nur ein Ziel erlaubt. Verwende eine Zeile dafür (kein \"Return\"!). Erlaubte Symbole sind 0-9, a-z, A-Z und <>=.\nBeispiel:\nx + y\n-786433 x1 + 655361 x2"; return "Geben Sie Ihr Ziel hier ein. Es ist nur ein Ziel erlaubt. Verwenden Sie eine Zeile dafür (kein 'Enter'!). Erlaubte Symbole sind 0-9, a-z, A-Z und <>=.\nBeispiel:\nx + y\n-786433 x1 + 655361 x2";
case "boxSubjTitle": case "boxSubjTitle":
return "Nebenbedingungen"; return "Nebenbedingungen";
case "boxSubjDesc": case "boxSubjDesc":
return "Gib hier dein Nebenbedingungen ein. Eines pro Zeile (trenne mit der 'Return'-Taste). Erlaubte Symbole sind 0-9, a-z, A-Z und <>=.\nBeispiel:\n+1 x + 2 y <= 15\n524321 x14 + 524305 x15 <= 4194303.5"; return "Geben Sie Ihre Nebenbedingungen hier ein. Eine pro Zeile (mit der 'Enter'-Taste trennen). Erlaubte Symbole sind 0-9, a-z, A-Z und <>=.\nBeispiel:\n+1 x + 2 y <= 15\n524321 x14 + 524305 x15 <= 4194303.5";
case "boxBoundsTitle": case "boxBoundsTitle":
return "Grenzen"; return "Grenzen";
case "boxBoundsDesc": case "boxBoundsDesc":
return "Gib hier deine Grenzen ein. Eine pro Zeile (trenne mit der 'Return'-Taste). Erlaubte Symbole sind 0-9, a-z, A-Z und <>=.\nBeispiel:\nx >= 0\nx > 0\n0 <= x1 <= 1"; return "Geben Sie Ihre Grenzen hier ein. Eine pro Zeile (mit der 'Enter'-Taste trennen). Erlaubte Symbole sind 0-9, a-z, A-Z und <>=.\nBeispiel:\nx >= 0\nx > 0\n0 <= x1 <= 1";
case "boxVarsTitle": case "boxVarsTitle":
return "Variablen"; return "Variablen";
case "boxVarsDesc": case "boxVarsDesc":
return "Liste alle deine Variablen auf. Eine pro Zeile (trenne mit der 'Return'-Taste). Erlaubte Symbole sind a-z, A-Z.\nBeispiel:\nx\ny"; return "Listen Sie alle Ihre Variablen auf. Eine pro Zeile (mit der 'Enter'-Taste trennen). Erlaubte Symbole sind a-z, A-Z.\nBeispiel:\nx\ny";
case "boxExportLP": case "boxExportLP":
return "Exportieren als LP"; return "Als LP exportieren";
case "boxOut": case "boxOut":
return "Geben Sie ein Problem und eine Aktionstaste ein, um die Ausgabe anzuzeigen..."; return "Geben Sie ein Problem ein und drücken Sie eine Aktionstaste, um die Ausgabe anzuzeigen...";
case "buttonCalc": case "buttonCalc":
return "Berechnen"; return "Berechnen";
case "etime":
return "Berechnungsdauer";
case "seconds":
return "Sekunden";
case "err_invalidInput":
return "Fehler: Ungültige Eingabe in";
case "err_nullInput":
return "Fehler: NULL- oder undefinierte Eingabe in";
case "err_invalidInput":
return "Fehler: Ungültige Eingabe oder fehlendes Zeichen in";
case "input_checks_successful":
return "Alle Eingabeprüfungen erfolgreich.";
case "input_checks_start":
return "Starte Eingabeprüfungen...";
case "obj_box":
return "Zielfeld";
case "subj_box":
return "Bedingungsfeld";
case "bounds_box":
return "Grenzenfeld";
case "vars_box":
return "Variablenfeld";
case "err_emptyBox":
return "Fehler: Leeres Textfeld.";
case "calculating":
return "Berechne...";
case "maximize":
return "Maximieren";
case "minimize":
return "Minimieren";
case "run_optimization":
return "Optimierung mit Eingaben wird ausgeführt";
case "startProblemSetup":
return "Starte Problemerstellung...";
case "succProblemSetup":
return "Problem erstellt.";
case "startScaling":
return "Skalieren des Problems...";
case "succScaling":
return "Skalierung erfolgreich.";
case "startOptimizationSimplex":
return "Starte Simplex-Optimierung...";
case "succOptimizationSimplex":
return "Simplex-Optimierung abgeschlossen.";
case "startOptimizationInteger":
return "Starte Ganzzahloptimierung...";
case "succOptimizationInteger":
return "Ganzzahloptimierung abgeschlossen.";
case "finalObjValue":
return "Endgültiger Zielfunktionswert";
case "varsValues":
return "Wert jeder Variable";
case "dualValues":
return "Dualwerte der Einschränkungen";
case "downloadPrepFileString":
return "Dateiinhalt wird vorbereitet...";
case "downloadPrepFile":
return "Datei wird vorbereitet...";
case "downloadStart":
return "Download wird gestartet.";
case "downloadPrep":
return "Download wird vorbereitet...";
case "downloadFetchInput":
return "Eingaben werden geladen...";
case "importing":
return "Importiere...";
default: default:
return "Fehler: Übersetzung nicht gefunden"; return input;
} }
} }
@@ -63,8 +129,74 @@ export default function text(lang: string, input: string): string {
return "Input a problem and an action button to display output..."; return "Input a problem and an action button to display output...";
case "buttonCalc": case "buttonCalc":
return "Calculate"; return "Calculate";
case "etime":
return "Elapsed time";
case "seconds":
return "seconds";
case "err_invalidInput":
return "Error: Invalid input in";
case "err_nullInput":
return "Error: NULL or undefined input in";
case "err_invalidInput":
return "Error: Invalid input or missing character in";
case "input_checks_successful":
return "All input checks successful."
case "input_checks_start":
return "Starting input checks...";
case "obj_box":
return "object box";
case "subj_box":
return "subject box";
case "bounds_box":
return "bounds box";
case "vars_box":
return "variables box";
case "err_emptyBox":
return "Error: Empty text box.";
case "calculating":
return "Calculating...";
case "maximize":
return "Maximize";
case "minimize":
return "Minimize";
case "run_optimization":
return "Running optimization with input";
case "startProblemSetup":
return "Starting problem setup...";
case "succProblemSetup":
return "Problem created.";
case "startScaling":
return "Scaling problem...";
case "succScaling":
return "Scaling successful.";
case "startOptimizationSimplex":
return "Starting simplex optimization...";
case "succOptimizationSimplex":
return "Simplex optimization complete.";
case "startOptimizationInteger":
return "Starting integer optimization...";
case "succOptimizationInteger":
return "Integer optimization complete.";
case "finalObjValue":
return "Final objective value";
case "varsValues":
return "Value of each variable";
case "dualValues":
return "Dual values of constraints";
case "downloadPrepFileString":
return "Preparing file content string...";
case "downloadPrepFile":
return "Preparing file...";
case "downloadStart":
return "Starting download.";
case "downloadPrep":
return "Preparing download...";
case "downloadFetchInput":
return "Fetching input...";
case "importing":
return "Importing...";
default: default:
return "Error: Translation Not Found"; return input;
} }
} }
+57 -39
View File
@@ -9,8 +9,6 @@ import text from "./lang"
// custom log so we can append the output dynamically // custom log so we can append the output dynamically
function customLog(input: string) { function customLog(input: string) {
// get language // get language
const lang = (document.getElementById('language_current') as HTMLSelectElement)?.value; const lang = (document.getElementById('language_current') as HTMLSelectElement)?.value;
@@ -34,6 +32,14 @@ function customLogClear() {
} }
} }
function getTranslation(input: string) {
// get language
const lang = (document.getElementById('language_current') as HTMLSelectElement)?.value;
// return translation
return text(lang, input);
}
function walltimeStopAndPrint(startpoint: number) { function walltimeStopAndPrint(startpoint: number) {
// calculating elapsed time as timestamp // calculating elapsed time as timestamp
let duration = Date.now() - startpoint; let duration = Date.now() - startpoint;
@@ -46,7 +52,8 @@ function walltimeStopAndPrint(startpoint: number) {
const durationFormatted = seconds + (milliseconds >= 0 ? "." : ".") + Math.abs(milliseconds).toFixed(3).slice(2); const durationFormatted = seconds + (milliseconds >= 0 ? "." : ".") + Math.abs(milliseconds).toFixed(3).slice(2);
// Printing elapsed time // Printing elapsed time
customLog("Elapsed time: " + durationFormatted + " seconds<br>"); customLog(getTranslation("etime") + ": " + durationFormatted + " " + getTranslation("seconds"));
customLog("");
// return durationFormatted; // return durationFormatted;
} }
@@ -56,11 +63,11 @@ function walltimeStart() {
} }
function isInputValidRegex(obj: string | undefined, subj: string | undefined, bounds: string | undefined, vars: string | undefined): boolean { function isInputValidRegex(obj: string | undefined, subj: string | undefined, bounds: string | undefined, vars: string | undefined): boolean {
customLog("Starting input checks..."); customLog("input_checks_start");
// standard case: input is undefined - invalid // standard case: input is undefined - invalid
if (obj === undefined || obj === null || subj === undefined || subj === null || bounds === undefined || bounds === null || vars === undefined || vars === null) { if (obj === undefined || obj === null || subj === undefined || subj === null || bounds === undefined || bounds === null || vars === undefined || vars === null) {
customLog("Error: Function isInputValidRegex received undefined or null input."); customLog(getTranslation("err_nullInput") + "function isInputValidRegex.");
return false; return false;
} }
@@ -68,7 +75,7 @@ function isInputValidRegex(obj: string | undefined, subj: string | undefined, bo
let regex = /^[ (\n)]*[\+-]? *((\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*)( *[\+-] *((\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*))*[ (\n)]*$/g; let regex = /^[ (\n)]*[\+-]? *((\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*)( *[\+-] *((\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*))*[ (\n)]*$/g;
let isValid = regex.test(obj); let isValid = regex.test(obj);
if (!isValid) { if (!isValid) {
customLog("Error: Invalid or missing character in object box."); customLog(getTranslation("err_invalidInput") + " " + getTranslation("obj_box") + ".");
return false; return false;
} }
@@ -76,46 +83,46 @@ function isInputValidRegex(obj: string | undefined, subj: string | undefined, bo
regex = /^([ (\n)]*[\+-]* *(\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*( *[\+-] *(\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*)* *((<=?)|(>=?)|=) *[\+-]? *\d+(.\d+)?[ (\n)]*)+$/g; regex = /^([ (\n)]*[\+-]* *(\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*( *[\+-] *(\d+(.\d+)? )?[a-zA-Z][a-zA-Z0-9]*)* *((<=?)|(>=?)|=) *[\+-]? *\d+(.\d+)?[ (\n)]*)+$/g;
isValid = regex.test(subj); isValid = regex.test(subj);
if (!isValid) { if (!isValid) {
customLog("Error: Invalid or missing character in subject box."); customLog(getTranslation("err_invalidInput") + " " + getTranslation("subj_box") + ".");
return false; return false;
} }
// RegEx check for subject // RegEx check for subject
regex = /[ (\n)]*(([a-zA-Z][a-zA-Z0-9]* *((<=?)|(>=?)|=) *\d(.\d+)?)|((\d(.\d+)?) *<=? *[a-zA-Z][a-zA-Z0-9]* *<= *(\d(.\d+)?)))[ (\n)]*/g; regex = /[ (\n)]*(([a-zA-Z][a-zA-Z0-9]* *((<=?)|(>=?)|=) *\d(.\d+)?)|((\d(.\d+)?) *<=? *[a-zA-Z][a-zA-Z0-9]* *<= *(\d(.\d+)?)))[ (\n)]*/g;
isValid = regex.test(bounds); isValid = regex.test(bounds);
if (!isValid) { if (!isValid) {
customLog("Error: Invalid or missing character in bounds box."); customLog(getTranslation("err_invalidInput") + " " + getTranslation("bounds_box") + ".");
return false; return false;
} }
// RegEx check for variables // RegEx check for variables
regex = /^ *([a-zA-Z][a-zA-Z0-9]*(\n)* *)+$/g; regex = /^ *([a-zA-Z][a-zA-Z0-9]*(\n)* *)+$/g;
isValid = regex.test(vars); isValid = regex.test(vars);
if (!isValid) { if (!isValid) {
customLog("Error: Invalid or missing character in variables box."); customLog(getTranslation("err_invalidInput") + " " + getTranslation("vars_box") + ".");
return false; return false;
} }
customLog("All input checks successful."); customLog("input_checks_successful");
customLog(""); customLog("");
return true; return true;
} }
function isInputFilled(obj: string | undefined, subj: string | undefined, bounds: string | undefined, vars: string | undefined) { function isInputFilled(obj: string | undefined, subj: string | undefined, bounds: string | undefined, vars: string | undefined) {
if (obj == "" || obj == null || obj == undefined) { if (obj == "" || obj == null || obj == undefined) {
customLog("Error: Empty input field."); customLog("err_emptyBox");
return false; return false;
} }
if (subj == "" || subj == null || subj == undefined) { if (subj == "" || subj == null || subj == undefined) {
customLog("Error: Empty input field."); customLog("err_emptyBox");
return false; return false;
} }
if (bounds == "" || bounds == null || bounds == undefined) { if (bounds == "" || bounds == null || bounds == undefined) {
customLog("Error: Empty input field."); customLog("err_emptyBox");
return false; return false;
} }
if (vars == "" || vars == null || vars == undefined) { if (vars == "" || vars == null || vars == undefined) {
customLog("Error: Empty input field."); customLog("err_emptyBox");
return false; return false;
} }
return true; return true;
@@ -124,7 +131,8 @@ function isInputFilled(obj: string | undefined, subj: string | undefined, bounds
export function calculate_click() { export function calculate_click() {
customLogClear(); customLogClear();
const timer = walltimeStart(); const timer = walltimeStart();
customLog("Calculating...<br>"); customLog("calculating");
customLog("");
let objective: string | undefined; let objective: string | undefined;
const objectiveElement = document.getElementById('objective'); const objectiveElement = document.getElementById('objective');
@@ -214,41 +222,47 @@ export function calculate_click() {
// customLog("<br><br>DEBUGGING<br><br>\nfunctions:<br>" + functions + "<br><br>variables:<br>" + variables + "<br><br>DEBUGGING END<br>"); // customLog("<br><br>DEBUGGING<br><br>\nfunctions:<br>" + functions + "<br><br>variables:<br>" + variables + "<br><br>DEBUGGING END<br>");
customLog("Running optimization with input: \"" + wholeText + "\"<br>"); customLog(getTranslation("run_optimization") + ": \"" + wholeText + "\"");
customLog("");
run(wholeText); run(wholeText);
walltimeStopAndPrint(timer); walltimeStopAndPrint(timer);
} }
function run(text: string) { function run(text: string) {
customLog("Starting problem setup..."); customLog("startProblemSetup");
let lp = GLPKAPI.glp_create_prob(); let lp = GLPKAPI.glp_create_prob();
GLPKAPI.glp_read_lp_from_string(lp, null, text); GLPKAPI.glp_read_lp_from_string(lp, null, text);
customLog("Problem created.<br>"); customLog("succProblemSetup");
customLog("");
customLog("Scaling problem..."); customLog("startScaling");
GLPKAPI.glp_scale_prob(lp, GLPKAPI.GLP_SF_AUTO); GLPKAPI.glp_scale_prob(lp, GLPKAPI.GLP_SF_AUTO);
customLog("Scaling complete.<br>"); customLog("succScaling");
customLog("");
customLog("Starting simplex optimization..."); customLog("startOptimizationSimplex");
let smcp = new GLPKAPI.SMCP({ presolve: GLPKAPI.GLP_ON }); let smcp = new GLPKAPI.SMCP({ presolve: GLPKAPI.GLP_ON });
GLPKAPI.glp_simplex(lp, smcp); GLPKAPI.glp_simplex(lp, smcp);
customLog("Simplex optimization complete.<br>"); customLog("succOptimizationSimplex");
customLog("");
customLog("Starting integer optimization..."); customLog("startOptimizationInteger");
let iocp = new GLPKAPI.IOCP({ presolve: GLPKAPI.GLP_ON }); let iocp = new GLPKAPI.IOCP({ presolve: GLPKAPI.GLP_ON });
GLPKAPI.glp_intopt(lp, iocp); GLPKAPI.glp_intopt(lp, iocp);
customLog("Integer optimization complete.<br>"); customLog("succOptimizationInteger");
customLog("");
// customLog("obj: " + GLPKAPI.glp_mip_obj_val(lp)); // customLog("obj: " + GLPKAPI.glp_mip_obj_val(lp));
customLog("<i>Final objective value: " + GLPKAPI.glp_mip_obj_val(lp) + "</i><br>"); customLog("<i>" + getTranslation("finalObjValue") + ": " + GLPKAPI.glp_mip_obj_val(lp) + "</i>");
customLog("Value of each variable:"); customLog("");
for (let i = 1; i <= GLPKAPI.glp_get_num_cols(lp) - 1; i++) { // "-1" to remove the "End-variable" from logs customLog(getTranslation("varsValues") + ":");
for (let i = 1; i <= GLPKAPI.glp_get_num_cols(lp); i++) {
customLog(GLPKAPI.glp_get_col_name(lp, i) + " = " + GLPKAPI.glp_mip_col_val(lp, i)); customLog(GLPKAPI.glp_get_col_name(lp, i) + " = " + GLPKAPI.glp_mip_col_val(lp, i));
} }
customLog(""); customLog("");
customLog("Dual values of constraints:"); customLog(getTranslation("dualValues") + ":");
for (let j = 1; j <= GLPKAPI.glp_get_num_rows(lp); j++) { for (let j = 1; j <= GLPKAPI.glp_get_num_rows(lp); j++) {
const dualValue = GLPKAPI.glp_get_row_dual(lp, j); // fetch dual const dualValue = GLPKAPI.glp_get_row_dual(lp, j); // fetch dual
const constraintName = GLPKAPI.glp_get_row_name(lp, j); const constraintName = GLPKAPI.glp_get_row_name(lp, j);
@@ -258,7 +272,8 @@ function run(text: string) {
} }
function downloadLPFormatting(objective: any, subject: any, bounds: any) { function downloadLPFormatting(objective: any, subject: any, bounds: any) {
customLog("Preparing file content string...<br>"); customLog(getTranslation("downloadPrepFileString"));
customLog("");
// ensure that all vars are strings // ensure that all vars are strings
const formattedObjective = typeof objective === 'string' ? objective : ''; const formattedObjective = typeof objective === 'string' ? objective : '';
@@ -287,19 +302,22 @@ function downloadLPFormatting(objective: any, subject: any, bounds: any) {
function downloadProblemDownload(content: string) { function downloadProblemDownload(content: string) {
customLog("Preparing file...<br>") customLog("downloadPrepFile");
customLog("");
const blob = new Blob([content], { type: 'text/plain' }); const blob = new Blob([content], { type: 'text/plain' });
const link = document.createElement('a'); const link = document.createElement('a');
link.href = URL.createObjectURL(blob); link.href = URL.createObjectURL(blob);
link.download = 'problem.txt'; // file name link.download = 'problem.txt'; // file name
link.click(); // starting download link.click(); // starting download
customLog("Starting download.") customLog("downloadStart");
} }
export function downloadLP() { export function downloadLP() {
customLogClear(); customLogClear();
customLog("Preparing download...<br>"); customLog("downloadPrep");
customLog("Fetching input...<br>") customLog("");
customLog("downloadFetchInput");
customLog("");
let objective: string | undefined; let objective: string | undefined;
const objectiveElement = document.getElementById('objective'); const objectiveElement = document.getElementById('objective');
@@ -344,7 +362,7 @@ export function downloadLP() {
export function import_click() { export function import_click() {
console.log("Importing..."); console.log("importing");
} }