Task 421: .MPS File Format
Task 421: .MPS File Format
File Format Specifications for .MPS
The .MPS file format is a standard for representing linear programming (LP) and mixed-integer programming (MIP) problems. It is text-based and can be in fixed or free format, with the fixed format using specific column positions for fields. The format includes sections for defining the problem name, rows (constraints and objective), columns (variables and coefficients), right-hand sides, bounds, ranges, and special ordered sets.
- List of all properties of this file format intrinsic to its file system
The properties refer to the structural elements and data fields defined in the MPS format specification. These are organized by sections and include:
- NAME section: Problem name (string, optional).
- OBJSENSE section (free format only): Objective direction (MIN, MINIMIZE, MAX, MAXIMIZE; optional, default is minimization in many solvers).
- OBJNAME section (free format only): Objective row name (string; optional, overrides first 'N' row).
- ROWS section: List of row names (8-character strings) and types ('E' for equality, 'L' for ≤, 'G' for ≥, 'N' for objective or free).
- COLUMNS section: Variable names (8-character strings), associated row names and coefficient values (floating-point), integer markers ('MARKER' with 'INTORG'/'INTEND' for MIP variables).
- RHS section: RHS vector name (string), row names and RHS values (floating-point).
- BOUNDS section (optional): Bound types ('UP' upper, 'LO' lower, 'FX' fixed, 'FR' free, 'MI' minus infinity, 'PL' plus infinity, 'BV' binary, 'LI' lower integer, 'UI' upper integer, 'SC' semi-continuous), bound set name (string), variable names, and bound values (floating-point).
- RANGES section (optional): Range vector name (string), row names and range values (floating-point, used to define ranged constraints).
- SOS section (optional): SOS types ('S1' to 'S9' for ordered sets), SOS names (strings), priorities (integers), variable names and weights (floating-point).
- ENDATA: End marker (required).
- General properties: Fixed format uses specific column positions (e.g., fields at columns 2-3, 5-12, 15-22, 25-36, 40-47, 50-61); free format uses space-separated fields. Comments start with '*' in column 1. Names are case-sensitive, up to 8 characters (longer in free format). Numbers in scientific notation (e.g., 1.23E+04).
These properties define the format's structure for encoding LP/MIP problems.
- Two direct download links for files of format .MPS
- https://people.sc.fsu.edu/~jburkardt/datasets/mps/adlittle.mps
- https://people.sc.fsu.edu/~jburkardt/datasets/mps/afiro.mps
- Ghost blog embedded HTML JavaScript for drag and drop .MPS file dump
Here is a complete HTML page with embedded JavaScript. It allows dragging and dropping an .MPS file, parses it (assuming fixed format for simplicity; handles core sections like NAME, ROWS, COLUMNS, RHS, BOUNDS; skips advanced like SOS/RANGES for brevity), extracts the properties, and dumps them to the screen in a readable format.
- Python class for .MPS handling
import os
class MPSHandler:
def __init__(self):
self.name = ''
self.rows = [] # list of dicts {'name': str, 'type': str}
self.variables = set()
self.coefficients = [] # list of dicts {'var': str, 'row': str, 'value': float}
self.rhs = [] # list of dicts {'row': str, 'value': float}
self.bounds = [] # list of dicts {'type': str, 'var': str, 'value': float or None}
def read(self, filepath):
if not os.path.exists(filepath):
raise FileNotFoundError(f"File {filepath} not found")
with open(filepath, 'r') as f:
lines = [line.rstrip() for line in f]
section = ''
current_rhs_name = ''
current_bound_name = ''
for line in lines:
if line.startswith('*'):
continue
if line == 'ENDATA':
break
parts = line.split()
if parts and parts[0] in ['NAME', 'ROWS', 'COLUMNS', 'RHS', 'BOUNDS']:
section = parts[0]
if section == 'NAME':
self.name = ' '.join(parts[1:])
continue
if section == 'ROWS':
row_type = line[1:3].strip()
row_name = line[4:12].strip()
if row_type and row_name:
self.rows.append({'name': row_name, 'type': row_type})
elif section == 'COLUMNS':
var_name = line[4:12].strip()
row1 = line[14:22].strip()
try:
val1 = float(line[24:36].strip())
except ValueError:
val1 = None
row2 = line[39:47].strip()
try:
val2 = float(line[49:61].strip())
except ValueError:
val2 = None
if var_name:
self.variables.add(var_name)
if row1 and val1 is not None:
self.coefficients.append({'var': var_name, 'row': row1, 'value': val1})
if row2 and val2 is not None:
self.coefficients.append({'var': var_name, 'row': row2, 'value': val2})
elif section == 'RHS':
current_rhs_name = line[4:12].strip()
row1 = line[14:22].strip()
try:
val1 = float(line[24:36].strip())
except ValueError:
val1 = None
row2 = line[39:47].strip()
try:
val2 = float(line[49:61].strip())
except ValueError:
val2 = None
if row1 and val1 is not None:
self.rhs.append({'row': row1, 'value': val1})
if row2 and val2 is not None:
self.rhs.append({'row': row2, 'value': val2})
elif section == 'BOUNDS':
bound_type = line[1:3].strip()
current_bound_name = line[4:12].strip()
var_name = line[14:22].strip()
try:
value = float(line[24:36].strip())
except ValueError:
value = None
if bound_type and var_name:
self.bounds.append({'type': bound_type, 'var': var_name, 'value': value})
self.variables = list(self.variables)
def print_properties(self):
print(f"Problem Name: {self.name}")
print("Rows:")
for r in self.rows:
print(f" {r['type']} {r['name']}")
print("Variables:", ', '.join(self.variables))
print("Coefficients:")
for c in self.coefficients:
print(f" {c['var']} in {c['row']}: {c['value']}")
print("RHS:")
for rh in self.rhs:
print(f" {rh['row']}: {rh['value']}")
print("Bounds:")
for b in self.bounds:
print(f" {b['type']} {b['var']}: {b['value']}")
def write(self, filepath):
with open(filepath, 'w') as f:
if self.name:
f.write(f"NAME {self.name}\n")
f.write("ROWS\n")
for r in self.rows:
f.write(f" {r['type']} {r['name']:<8}\n")
f.write("COLUMNS\n")
# Group coefficients by variable for writing
var_coeffs = {}
for c in self.coefficients:
if c['var'] not in var_coeffs:
var_coeffs[c['var']] = []
var_coeffs[c['var']].append((c['row'], c['value']))
for var in sorted(var_coeffs):
coeffs = var_coeffs[var]
for i in range(0, len(coeffs), 2):
line = f" {var:<8}"
row1, val1 = coeffs[i]
line += f" {row1:<8} {val1:12.5E}"
if i + 1 < len(coeffs):
row2, val2 = coeffs[i+1]
line += f" {row2:<8} {val2:12.5E}"
f.write(line + '\n')
f.write("RHS\n")
# Assume single RHS, write in pairs
for i in range(0, len(self.rhs), 2):
line = " RHS1 "
rh1 = self.rhs[i]
line += f"{rh1['row']:<8} {rh1['value']:12.5E}"
if i + 1 < len(self.rhs):
rh2 = self.rhs[i+1]
line += f" {rh2['row']:<8} {rh2['value']:12.5E}"
f.write(line + '\n')
if self.bounds:
f.write("BOUNDS\n")
for b in self.bounds:
value_str = f"{b['value']:12.5E}" if b['value'] is not None else ''
f.write(f" {b['type']} BND1 {b['var']:<8} {value_str}\n")
f.write("ENDATA\n")
# Example usage:
# handler = MPSHandler()
# handler.read('example.mps')
# handler.print_properties()
# handler.write('output.mps')
- Java class for .MPS handling
import java.io.*;
import java.util.*;
public class MPSHandler {
private String name = "";
private List<Map<String, String>> rows = new ArrayList<>(); // name, type
private Set<String> variables = new HashSet<>();
private List<Map<String, Object>> coefficients = new ArrayList<>(); // var, row, value (Double)
private List<Map<String, Object>> rhs = new ArrayList<>(); // row, value (Double)
private List<Map<String, Object>> bounds = new ArrayList<>(); // type, var, value (Double or null)
public void read(String filepath) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filepath));
String line;
String section = "";
String currentRHSName = "";
String currentBoundName = "";
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("*")) continue;
if (line.equals("ENDATA")) break;
String[] parts = line.split("\\s+");
if (parts.length > 0 && Arrays.asList("NAME", "ROWS", "COLUMNS", "RHS", "BOUNDS").contains(parts[0])) {
section = parts[0];
if (section.equals("NAME")) {
name = line.substring(14).trim();
}
continue;
}
if (section.equals("ROWS")) {
String rowType = line.substring(1, 3).trim();
String rowName = line.substring(4, 12).trim();
if (!rowType.isEmpty() && !rowName.isEmpty()) {
Map<String, String> row = new HashMap<>();
row.put("name", rowName);
row.put("type", rowType);
rows.add(row);
}
} else if (section.equals("COLUMNS")) {
String varName = line.substring(4, 12).trim();
String row1 = line.substring(14, 22).trim();
Double val1 = parseDoubleSafe(line.substring(24, 36).trim());
String row2 = line.substring(39, 47).trim();
Double val2 = parseDoubleSafe(line.substring(49, 61).trim());
if (!varName.isEmpty()) variables.add(varName);
if (!row1.isEmpty() && val1 != null) {
Map<String, Object> coeff = new HashMap<>();
coeff.put("var", varName);
coeff.put("row", row1);
coeff.put("value", val1);
coefficients.add(coeff);
}
if (!row2.isEmpty() && val2 != null) {
Map<String, Object> coeff = new HashMap<>();
coeff.put("var", varName);
coeff.put("row", row2);
coeff.put("value", val2);
coefficients.add(coeff);
}
} else if (section.equals("RHS")) {
currentRHSName = line.substring(4, 12).trim();
String row1 = line.substring(14, 22).trim();
Double val1 = parseDoubleSafe(line.substring(24, 36).trim());
String row2 = line.substring(39, 47).trim();
Double val2 = parseDoubleSafe(line.substring(49, 61).trim());
if (!row1.isEmpty() && val1 != null) {
Map<String, Object> rh = new HashMap<>();
rh.put("row", row1);
rh.put("value", val1);
rhs.add(rh);
}
if (!row2.isEmpty() && val2 != null) {
Map<String, Object> rh = new HashMap<>();
rh.put("row", row2);
rh.put("value", val2);
rhs.add(rh);
}
} else if (section.equals("BOUNDS")) {
String boundType = line.substring(1, 3).trim();
currentBoundName = line.substring(4, 12).trim();
String varName = line.substring(14, 22).trim();
Double value = parseDoubleSafe(line.substring(24, 36).trim());
if (!boundType.isEmpty() && !varName.isEmpty()) {
Map<String, Object> bound = new HashMap<>();
bound.put("type", boundType);
bound.put("var", varName);
bound.put("value", value);
bounds.add(bound);
}
}
}
reader.close();
}
private Double parseDoubleSafe(String s) {
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) {
return null;
}
}
public void printProperties() {
System.out.println("Problem Name: " + name);
System.out.println("Rows:");
for (Map<String, String> r : rows) {
System.out.println(" " + r.get("type") + " " + r.get("name"));
}
System.out.println("Variables: " + String.join(", ", variables));
System.out.println("Coefficients:");
for (Map<String, Object> c : coefficients) {
System.out.println(" " + c.get("var") + " in " + c.get("row") + ": " + c.get("value"));
}
System.out.println("RHS:");
for (Map<String, Object> rh : rhs) {
System.out.println(" " + rh.get("row") + ": " + rh.get("value"));
}
System.out.println("Bounds:");
for (Map<String, Object> b : bounds) {
System.out.println(" " + b.get("type") + " " + b.get("var") + ": " + b.get("value"));
}
}
public void write(String filepath) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(filepath));
if (!name.isEmpty()) {
writer.write("NAME " + name + "\n");
}
writer.write("ROWS\n");
for (Map<String, String> r : rows) {
writer.write(String.format(" %s %-8s\n", r.get("type"), r.get("name")));
}
writer.write("COLUMNS\n");
Map<String, List<Map<String, Object>>> varCoeffs = new HashMap<>();
for (Map<String, Object> c : coefficients) {
String var = (String) c.get("var");
varCoeffs.computeIfAbsent(var, k -> new ArrayList<>()).add(c);
}
for (String var : new TreeSet<>(varCoeffs.keySet())) {
List<Map<String, Object>> coeffs = varCoeffs.get(var);
for (int i = 0; i < coeffs.size(); i += 2) {
StringBuilder sb = new StringBuilder(String.format(" %-8s", var));
Map<String, Object> c1 = coeffs.get(i);
sb.append(String.format(" %-8s %12.5E", c1.get("row"), c1.get("value")));
if (i + 1 < coeffs.size()) {
Map<String, Object> c2 = coeffs.get(i + 1);
sb.append(String.format(" %-8s %12.5E", c2.get("row"), c2.get("value")));
}
writer.write(sb.toString() + "\n");
}
}
writer.write("RHS\n");
for (int i = 0; i < rhs.size(); i += 2) {
StringBuilder sb = new StringBuilder(" RHS1 ");
Map<String, Object> rh1 = rhs.get(i);
sb.append(String.format("%-8s %12.5E", rh1.get("row"), rh1.get("value")));
if (i + 1 < rhs.size()) {
Map<String, Object> rh2 = rhs.get(i + 1);
sb.append(String.format(" %-8s %12.5E", rh2.get("row"), rh2.get("value")));
}
writer.write(sb.toString() + "\n");
}
if (!bounds.isEmpty()) {
writer.write("BOUNDS\n");
for (Map<String, Object> b : bounds) {
String valueStr = b.get("value") != null ? String.format("%12.5E", b.get("value")) : "";
writer.write(String.format(" %s BND1 %-8s %s\n", b.get("type"), b.get("var"), valueStr));
}
}
writer.write("ENDATA\n");
writer.close();
}
// Example usage:
// public static void main(String[] args) throws IOException {
// MPSHandler handler = new MPSHandler();
// handler.read("example.mps");
// handler.printProperties();
// handler.write("output.mps");
// }
}
- JavaScript class for .MPS handling
This is a browser-compatible class using File object for "open" (via FileReader). For Node.js, it could use fs, but here it's for browser consistency with drag/drop.
class MPSHandler {
constructor() {
this.name = '';
this.rows = []; // [{name: str, type: str}]
this.variables = new Set();
this.coefficients = []; // [{var: str, row: str, value: number}]
this.rhs = []; // [{row: str, value: number}]
this.bounds = []; // [{type: str, var: str, value: number|null}]
}
async read(file) { // file is File object
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const content = event.target.result;
this.parse(content);
resolve();
};
reader.onerror = reject;
reader.readAsText(file);
});
}
parse(content) {
const lines = content.split('\n').map(line => line.trimEnd());
let section = '';
for (let line of lines) {
if (line.startsWith('*')) continue;
if (line === 'ENDATA') break;
const parts = line.split(/\s+/);
if (parts[0] && ['NAME', 'ROWS', 'COLUMNS', 'RHS', 'BOUNDS'].includes(parts[0])) {
section = parts[0];
if (section === 'NAME') this.name = parts.slice(1).join(' ');
continue;
}
if (section === 'ROWS') {
const type = line.substring(1,3).trim();
const name = line.substring(4,12).trim();
if (type && name) this.rows.push({name, type});
} else if (section === 'COLUMNS') {
const varName = line.substring(4,12).trim();
const row1 = line.substring(14,22).trim();
const val1 = parseFloat(line.substring(24,36));
const row2 = line.substring(39,47).trim();
const val2 = parseFloat(line.substring(49,61));
if (varName) this.variables.add(varName);
if (row1 && !isNaN(val1)) this.coefficients.push({var: varName, row: row1, value: val1});
if (row2 && !isNaN(val2)) this.coefficients.push({var: varName, row: row2, value: val2});
} else if (section === 'RHS') {
const row1 = line.substring(14,22).trim();
const val1 = parseFloat(line.substring(24,36));
const row2 = line.substring(39,47).trim();
const val2 = parseFloat(line.substring(49,61));
if (row1 && !isNaN(val1)) this.rhs.push({row: row1, value: val1});
if (row2 && !isNaN(val2)) this.rhs.push({row: row2, value: val2});
} else if (section === 'BOUNDS') {
const type = line.substring(1,3).trim();
const varName = line.substring(14,22).trim();
const value = parseFloat(line.substring(24,36));
if (type && varName) this.bounds.push({type, var: varName, value: isNaN(value) ? null : value});
}
}
this.variables = Array.from(this.variables);
}
printProperties() {
console.log(`Problem Name: ${this.name}`);
console.log('Rows:');
this.rows.forEach(r => console.log(` ${r.type} ${r.name}`));
console.log('Variables:', this.variables.join(', '));
console.log('Coefficients:');
this.coefficients.forEach(c => console.log(` ${c.var} in ${c.row}: ${c.value}`));
console.log('RHS:');
this.rhs.forEach(r => console.log(` ${r.row}: ${r.value}`));
console.log('Bounds:');
this.bounds.forEach(b => console.log(` ${b.type} ${b.var}: ${b.value}`));
}
write() {
let output = '';
if (this.name) output += `NAME ${this.name}\n`;
output += 'ROWS\n';
this.rows.forEach(r => {
output += ` ${r.type} ${r.name.padEnd(8)}\n`;
});
output += 'COLUMNS\n';
const varCoeffs = {};
this.coefficients.forEach(c => {
if (!varCoeffs[c.var]) varCoeffs[c.var] = [];
varCoeffs[c.var].push({row: c.row, value: c.value});
});
Object.keys(varCoeffs).sort().forEach(varName => {
const coeffs = varCoeffs[varName];
for (let i = 0; i < coeffs.length; i += 2) {
let line = ` ${varName.padEnd(8)}`;
line += ` ${coeffs[i].row.padEnd(8)} ${coeffs[i].value.toExponential(5).padStart(12)}`;
if (i + 1 < coeffs.length) {
line += ` ${coeffs[i+1].row.padEnd(8)} ${coeffs[i+1].value.toExponential(5).padStart(12)}`;
}
output += line + '\n';
}
});
output += 'RHS\n';
for (let i = 0; i < this.rhs.length; i += 2) {
let line = ' RHS1 ';
line += `${this.rhs[i].row.padEnd(8)} ${this.rhs[i].value.toExponential(5).padStart(12)}`;
if (i + 1 < this.rhs.length) {
line += ` ${this.rhs[i+1].row.padEnd(8)} ${this.rhs[i+1].value.toExponential(5).padStart(12)}`;
}
output += line + '\n';
}
if (this.bounds.length > 0) {
output += 'BOUNDS\n';
this.bounds.forEach(b => {
const valueStr = b.value !== null ? b.value.toExponential(5).padStart(12) : '';
output += ` ${b.type} BND1 ${b.var.padEnd(8)} ${valueStr}\n`;
});
}
output += 'ENDATA\n';
return output; // Return string; can be saved to file via blob/download
}
}
// Example usage:
// const handler = new MPSHandler();
// handler.read(myFileObject).then(() => {
// handler.printProperties();
// const mpsContent = handler.write();
// // To save: const blob = new Blob([mpsContent], {type: 'text/plain'});
// // const url = URL.createObjectURL(blob);
// // const a = document.createElement('a');
// // a.href = url;
// // a.download = 'output.mps';
// // a.click();
// });
- C class (using C++ for class support) for .MPS handling
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iomanip>
#include <sstream>
struct Row {
std::string name;
std::string type;
};
struct Coefficient {
std::string var;
std::string row;
double value;
};
struct RHS {
std::string row;
double value;
};
struct Bound {
std::string type;
std::string var;
double value; // Use NAN for null
};
class MPSHandler {
public:
std::string name;
std::vector<Row> rows;
std::set<std::string> variables_set;
std::vector<std::string> variables;
std::vector<Coefficient> coefficients;
std::vector<RHS> rhs;
std::vector<Bound> bounds;
void read(const std::string& filepath) {
std::ifstream file(filepath);
if (!file.is_open()) {
throw std::runtime_error("File not found");
}
std::string line;
std::string section = "";
std::string current_rhs_name = "";
std::string current_bound_name = "";
while (std::getline(file, line)) {
// Trim trailing spaces
line.erase(line.find_last_not_of(" \n\r\t") + 1);
if (line.empty() || line[0] == '*') continue;
if (line == "ENDATA") break;
std::istringstream iss(line);
std::string first;
iss >> first;
if (first == "NAME" || first == "ROWS" || first == "COLUMNS" || first == "RHS" || first == "BOUNDS") {
section = first;
if (section == "NAME") {
name = line.substr(14);
// Trim name
name.erase(0, name.find_first_not_of(" \t"));
name.erase(name.find_last_not_of(" \t") + 1);
}
continue;
}
if (section == "ROWS") {
std::string row_type = line.substr(1, 2);
row_type.erase(row_type.find_last_not_of(" \t") + 1);
std::string row_name = line.substr(4, 8);
row_name.erase(row_name.find_last_not_of(" \t") + 1);
if (!row_type.empty() && !row_name.empty()) {
rows.push_back({row_name, row_type});
}
} else if (section == "COLUMNS") {
std::string var_name = line.substr(4, 8);
var_name.erase(var_name.find_last_not_of(" \t") + 1);
std::string row1 = line.substr(14, 8);
row1.erase(row1.find_last_not_of(" \t") + 1);
double val1;
std::string val1_str = line.substr(24, 12);
std::istringstream(val1_str) >> val1;
std::string row2 = "";
double val2 = 0.0;
if (line.length() >= 49) {
row2 = line.substr(39, 8);
row2.erase(row2.find_last_not_of(" \t") + 1);
std::string val2_str = line.substr(49, 12);
std::istringstream(val2_str) >> val2;
}
if (!var_name.empty()) variables_set.insert(var_name);
if (!row1.empty() && !std::isnan(val1)) {
coefficients.push_back({var_name, row1, val1});
}
if (!row2.empty() && !std::isnan(val2)) {
coefficients.push_back({var_name, row2, val2});
}
} else if (section == "RHS") {
current_rhs_name = line.substr(4, 8);
current_rhs_name.erase(current_rhs_name.find_last_not_of(" \t") + 1);
std::string row1 = line.substr(14, 8);
row1.erase(row1.find_last_not_of(" \t") + 1);
double val1;
std::string val1_str = line.substr(24, 12);
std::istringstream(val1_str) >> val1;
std::string row2 = "";
double val2 = 0.0;
if (line.length() >= 49) {
row2 = line.substr(39, 8);
row2.erase(row2.find_last_not_of(" \t") + 1);
std::string val2_str = line.substr(49, 12);
std::istringstream(val2_str) >> val2;
}
if (!row1.empty() && !std::isnan(val1)) {
rhs.push_back({row1, val1});
}
if (!row2.empty() && !std::isnan(val2)) {
rhs.push_back({row2, val2});
}
} else if (section == "BOUNDS") {
std::string bound_type = line.substr(1, 2);
bound_type.erase(bound_type.find_last_not_of(" \t") + 1);
current_bound_name = line.substr(4, 8);
current_bound_name.erase(current_bound_name.find_last_not_of(" \t") + 1);
std::string var_name = line.substr(14, 8);
var_name.erase(var_name.find_last_not_of(" \t") + 1);
double value;
std::string value_str = line.substr(24, 12);
std::istringstream(value_str) >> value;
if (!bound_type.empty() && !var_name.empty()) {
bounds.push_back({bound_type, var_name, std::isnan(value) ? NAN : value});
}
}
}
variables.assign(variables_set.begin(), variables_set.end());
file.close();
}
void printProperties() {
std::cout << "Problem Name: " << name << std::endl;
std::cout << "Rows:" << std::endl;
for (const auto& r : rows) {
std::cout << " " << r.type << " " << r.name << std::endl;
}
std::cout << "Variables: ";
for (size_t i = 0; i < variables.size(); ++i) {
std::cout << variables[i];
if (i < variables.size() - 1) std::cout << ", ";
}
std::cout << std::endl;
std::cout << "Coefficients:" << std::endl;
for (const auto& c : coefficients) {
std::cout << " " << c.var << " in " << c.row << ": " << c.value << std::endl;
}
std::cout << "RHS:" << std::endl;
for (const auto& rh : rhs) {
std::cout << " " << rh.row << ": " << rh.value << std::endl;
}
std::cout << "Bounds:" << std::endl;
for (const auto& b : bounds) {
std::cout << " " << b.type << " " << b.var << ": ";
if (std::isnan(b.value)) std::cout << "null";
else std::cout << b.value;
std::cout << std::endl;
}
}
void write(const std::string& filepath) {
std::ofstream file(filepath);
if (!file.is_open()) {
throw std::runtime_error("Cannot open file for writing");
}
if (!name.empty()) {
file << "NAME " << name << "\n";
}
file << "ROWS\n";
for (const auto& r : rows) {
file << " " << r.type << " " << std::left << std::setw(8) << r.name << "\n";
}
file << "COLUMNS\n";
std::map<std::string, std::vector<std::pair<std::string, double>>> var_coeffs;
for (const auto& c : coefficients) {
var_coeffs[c.var].emplace_back(c.row, c.value);
}
for (const auto& [var, coeffs] : var_coeffs) {
for (size_t i = 0; i < coeffs.size(); i += 2) {
file << " " << std::left << std::setw(8) << var;
file << " " << std::left << std::setw(8) << coeffs[i].first << " " << std::scientific << std::setprecision(5) << std::setw(12) << coeffs[i].second;
if (i + 1 < coeffs.size()) {
file << " " << std::left << std::setw(8) << coeffs[i + 1].first << " " << std::scientific << std::setprecision(5) << std::setw(12) << coeffs[i + 1].second;
}
file << "\n";
}
}
file << "RHS\n";
for (size_t i = 0; i < rhs.size(); i += 2) {
file << " RHS1 " << std::left << std::setw(8) << rhs[i].row << " " << std::scientific << std::setprecision(5) << std::setw(12) << rhs[i].value;
if (i + 1 < rhs.size()) {
file << " " << std::left << std::setw(8) << rhs[i + 1].row << " " << std::scientific << std::setprecision(5) << std::setw(12) << rhs[i + 1].value;
}
file << "\n";
}
if (!bounds.empty()) {
file << "BOUNDS\n";
for (const auto& b : bounds) {
file << " " << b.type << " BND1 " << std::left << std::setw(8) << b.var;
if (!std::isnan(b.value)) {
file << " " << std::scientific << std::setprecision(5) << std::setw(12) << b.value;
}
file << "\n";
}
}
file << "ENDATA\n";
file.close();
}
};
// Example usage:
// int main() {
// MPSHandler handler;
// try {
// handler.read("example.mps");
// handler.printProperties();
// handler.write("output.mps");
// } catch (const std::exception& e) {
// std::cerr << e.what() << std::endl;
// }
// return 0;
// }