Coder Social home page Coder Social logo

orloge's Introduction

Orloge

Build Status

What and why

The idea of this project is to permit a fast and easy parsing of the log files from different solvers, specifically 'operations research' (OR) logs.

There exist bigger, and more robust libraries. In particular, IPET. The trouble I had was that it deals with too many benchmarking and GUI things and I wanted something simple I could modify and build on top.

In any case, a lot of the ideas and parsing strings were obtained or adapted from IPET, to whom I am graceful.

The supported solvers for the time being are: GUROBI, CPLEX and CBC. Specially the two first ones.

How

The basic idea is just to provide a unique interface function like the following:

import orloge as ol
ol.get_info_solver(path_to_solver_log, solver_name)

This returns a python dictionary with a lot of information from the log (see Examples below).

Installation

pip install orloge

or, for the development version:

pip install https://github.com/pchtsp/orloge/archive/master.zip

Testing

Run the command

python -m unittest test

if the output says OK, all tests were passed.

Reference

Main parameters

The most common parameters to extract are: best_bound, best_solution and time. These three parameters are obtained at the end of the solving process and summarize the best relaxed objective value obtained, the best integer objective value obtained and the time it took to do the solving.

Cuts

The cuts information can be accessed by the cuts_info key. It offers the best known bound after the cut phase has ended, the best solution (if any) after the cuts and the number of cuts made of each type.

Matrix

There are two matrices that are provided. The matrix key returns the number of variables, constraints and non-zero values before the pre-processing of the solver. The matrix_post key returns these same values after the pre-processing has been done.

Progress

The progress key returns a raw pandas Dataframe with the all the progress information the solver gives. Including the times, the gap, the best bound, the best solution, the iterations, nodes, among other. This table can vary in number of columns between solvers but the names of the columns are normalized so as to have the same name for the same information.

Status

The status is given in several ways. First, a raw string extraction is returned in status. Then, a normalized one using codes is given via sol_code and status_code keys. sol_code gives information about the quality of the solution obtained. status_code gives details about the status of the solver after finishing (mainly, the reason it stopped).

Other

There is also information about the pre-solving phase, the first bound and the first solution. Also, there's information about the time it took to solve the root node.

Examples

import orloge as ol
ol.get_info_solver('tests/data/cbc298-app1-2.out', 'CBC')

Would produce the following:

{'best_bound': -96.111283,
 'best_solution': None,
 'cut_info': {'best_bound': -210.09571,
              'best_solution': 1e+50,
              'cuts': None,
              'time': None},
 'first_relaxed': -210.09571,
 'first_solution': 1e+50,
 'gap': None,
 'matrix': {'constraints': 53467, 'nonzeros': 199175, 'variables': 26871},
 'matrix_post': {'constraints': 26555, 'nonzeros': 195875, 'variables': 13265},
 'nodes': 31867,
 'presolve': None,
 'progress':       
 Node NodesLeft BestInteger CutsBestBound     Time
0        0         1       1e+50    -210.09571    32.83
1      100        11       1e+50    -210.09571   124.49
..     ...       ...         ...           ...      ...
[319 rows x 5 columns],
 'rootTime': None,
 'sol_code': 0,
 'solver': 'CBC',
 'status': 'Stopped on time limit',
 'status_code': -4,
 'time': 7132.49,
 'version': '2.9.8'}

And another example, this time using GUROBI:

import orloge as ol
ol.get_info_solver('tests/data/gurobi700-app1-2.out', 'GUROBI')

Creates the following output:

{'best_bound': -41.0,
 'best_solution': -41.0,
 'cut_info': {'best_bound': -167.97894,
              'best_solution': -41.0,
              'cuts': {'Clique': 1,
                       'Gomory': 16,
                       'Implied bound': 23,
                       'MIR': 22},
              'time': 21.0},
 'first_relaxed': -178.94318,
 'first_solution': -41.0,
 'gap': 0.0,
 'matrix': {'constraints': 53467, 'nonzeros': 199175, 'variables': 26871},
 'matrix_post': {'constraints': 35616, 'nonzeros': 149085, 'variables': 22010},
 'nodes': 526.0,
 'presolve': {'cols': 4861, 'rows': 17851, 'time': 3.4},
 'progress':    
 Node NodesLeft   Objective Depth ...  CutsBestBound    Gap ItpNode Time
0     0         0  -178.94318     0 ...     -178.94318   336%    None   4s
1     0         0  -171.91701     0 ...     -171.91701   319%    None  15s
2     0         0  -170.97660     0 ...     -170.97660   317%    None  15s
[26 rows x 10 columns],
 'rootTime': 0.7,
 'sol_code': 1,
 'solver': 'GUROBI',
 'status': 'Optimal solution found',
 'status_code': 1,
 'time': 46.67,
 'version': '7.0.0'}

Parsing the complete progress table helps anyone who later wants to analyze the raw solution process. I've tried to use the status codes and solution codes present in PuLP.

orloge's People

Contributors

pchtsp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

orloge's Issues

Parser for GUROBI is not getting the latest log info

I am now testing out this plugin with GUROBI as my solver, and it seems that it is not parsing the latest log information. See attached log file for reference (reformatted as a .txt file). The parsed output should have the gap = 0.3040% however it is still printing the gap as 69.1818% from the first output in the log. I also attached a screenshot of the command prompt output for reference. I also am pasting some relevant code for this example as well:

def configure_solver():
    if GUROBI().available():
        solver = GUROBI(logPath='C:/Users/ebongo/Documents/ABRA/ace/testLog.out')

    elif CPLEX_CMD().available():
        solver = CPLEX_CMD(msg=1, logPath='C:/Users/ebongo/Documents/ABRA/ace/testLog.out')
        
    elif PULP_CBC_CMD().available():
        solver = PULP_CBC_CMD(msg=1, logPath='C:/Users/ebongo/Documents/ABRA/ace/testLog.out')

    else:
        logger.warning("No solver found")

    solver.optionsDict["gapRel"] = params.MIP_gap
    solver.msg = 1  # display output to console

    # set the solver time limit
    if params.use_time_limit:
        solver.timeLimit = params.time_limit

    return solver

    model.writeLP('ABRA.lp')
    solver = configure_solver()
    model.solve(solver)

    solver_output_dict = ol.get_info_solver('C:/Users/ebongo/Documents/ABRA/ace/testLog.out', 'GUROBI')
    best_bound = solver_output_dict["best_bound"]
    best_solution = solver_output_dict["best_solution"]
    rel_gap = solver_output_dict["gap"]
    print(solver_output_dict)
    logger.info("Best bound: %s" % best_bound)
    logger.info("Best solution: %s" % best_solution)
    logger.info("Relative gap: %s" % rel_gap)

gurobiLog
testLog.txt

[CBC & GUROBI] parser failed

Orloge cannot correctly parse the following logs.
In fact, status and time cannot be retrieved (and some other fields)

CBC

Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 

command line - /home/vepain/Documents/Enseignements/ro_recherche_operationnelle/TP/.venv_39/lib/python3.9/site-packages/pulp/apis/../solverdir/cbc/linux/64/cbc /tmp/07c96077d3cf41a984ea75769ec57f9d-pulp.mps branch printingOptions all solution /tmp/07c96077d3cf41a984ea75769ec57f9d-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 9 COLUMNS
At line 28 RHS
At line 33 BOUNDS
At line 34 ENDATA
Problem MODEL has 4 rows, 4 columns and 14 elements
Coin0008I MODEL read with 0 errors
Presolve 4 (0) rows, 4 (0) columns and 14 (0) elements
0  Obj 0 Primal inf 7.0999996 (4)
2  Obj 90
Optimal - objective value 90
Optimal objective 90 - 2 iterations time 0.002
Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00

GUROBI


Gurobi 9.1.2 (linux64, gurobi_cl) logging started Wed Sep  8 18:28:59 2021

Academic license - for non-commercial use only - expires 2021-11-05
Using license file /home/vepain/gurobi.lic
Set parameter LogFile to value ./CBC_simple_ex.log

Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (linux64)
Copyright (c) 2021, Gurobi Optimization, LLC

Read LP format model from file /tmp/ab4c77a23d094b84b3ea1d9e7032db87-pulp.lp
Reading time = 0.00 seconds
Totat_cost: 4 rows, 4 columns, 14 nonzeros
Thread count: 4 physical cores, 8 logical processors, using up to 8 threads
Optimize a model with 4 rows, 4 columns and 14 nonzeros
Model fingerprint: 0xf5d9a7ca
Coefficient statistics:
  Matrix range     [1e+00, 5e+02]
  Objective range  [2e+01, 8e+01]
  Bounds range     [0e+00, 0e+00]
  RHS range        [6e+00, 5e+02]
Presolve time: 0.00s
Presolved: 4 rows, 4 columns, 14 nonzeros

Iteration    Objective       Primal Inf.    Dual Inf.      Time
       0    0.0000000e+00   1.512500e+02   0.000000e+00      0s
       2    9.0000000e+01   0.000000e+00   0.000000e+00      0s

Solved in 2 iterations and 0.00 seconds
Optimal objective  9.000000000e+01

Wrote result file '/tmp/ab4c77a23d094b84b3ea1d9e7032db87-pulp.sol'

ol.get_info_log_solver() function not working

I tried this: ol.get_info_log_solver('C:/Users/ebongo/AppData/Local/Programs/Python/Python38/Lib/site-packages/pulp/solverdir/cbc/win/64', 'PULP_CBC_CMD')

But I keep receiving this error: "AttributeError: module 'orloge' has no attribute 'get_info_log_solver'"
Am I referencing this function incorrectly? The log that this outputs would be extremely useful for my project so any help with this would be greatly appreciated.

[Gurobi log] Parser status_code fails if Warning line

Description

Orloge fails retrieving at least 'status_code' Gurobi log value because of a Warning line (see the end of the following log file)

To reproduce the bug

Code

from orloge import get_info_solver

log_path = './log_gurobi.log'
log = get_info_solver(log_path, 'GUROBI')
print(log['status_code'] is None)  # True

Log text file

log_gurobi.log

Gurobi 9.1.2 (linux64, gurobi_cl) logging started Tue Sep  7 13:55:23 2021

Academic license - for non-commercial use only - expires 2021-11-05
Using license file /home/vepain/gurobi.lic
Set parameter LogFile to value tests/longest_path/solver_gurobi_gat.log

Gurobi Optimizer version 9.1.2 build v9.1.2rc0 (linux64)
Copyright (c) 2021, Gurobi Optimization, LLC

Read LP format model from file /tmp/037e4e7ce19f41e68947cd514fd009ba-pulp.lp
Reading time = 0.01 seconds
OBJ: 3939 rows, 2656 columns, 9894 nonzeros
Thread count: 4 physical cores, 8 logical processors, using up to 8 threads
Optimize a model with 3939 rows, 2656 columns and 9894 nonzeros
Model fingerprint: 0xa3b7c9e3
Variable types: 816 continuous, 1840 integer (1326 binary)
Coefficient statistics:
  Matrix range     [1e+00, 2e+06]
  Objective range  [1e+00, 1e+00]
  Bounds range     [1e+00, 2e+06]
  RHS range        [1e+00, 5e+03]
Presolve removed 1741 rows and 1255 columns
Presolve time: 0.05s
Presolved: 2198 rows, 1401 columns, 6851 nonzeros
Variable types: 519 continuous, 882 integer (492 binary)
Found heuristic solution: objective 858381.00000

Root relaxation: cutoff, 1702 iterations, 0.06 seconds

    Nodes    |    Current Node    |     Objective Bounds      |     Work
 Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

     0     0     cutoff    0      858381.000 858381.000  0.00%     -    0s

Explored 0 nodes (1702 simplex iterations) in 0.12 seconds
Thread count was 8 (of 8 available processors)

Solution count 1: 858381 

Optimal solution found (tolerance 1.00e-04)
Warning: max constraint violation (1.1887e-06) exceeds tolerance
Best objective 8.583810000000e+05, best bound 8.583810000000e+05, gap 0.0000%

Wrote result file '/tmp/037e4e7ce19f41e68947cd514fd009ba-pulp.sol'

Thank you in advance for your help !

elapsed time in cplex progress missing for version 20.1

The latest version of cplex changed slightly the format of the log: the times at the end are justified to the right and hence preceded by a variable number of white spaces.

The log attached ends with:
Total (root+branch&cut) = 300.03 sec. (91622.74 ticks)

Method CPLEX.get_time(self) parses this line with:

regex = "Total (root+branch&cut) = {0} sec. ({0} ticks)".format(self.numberSearch)

That fails, but if changed to:

regex = "Total (root+branch&cut) =\s+{0} sec. ({0} ticks)".format(self.numberSearch)

then all works as expected.

trivial.True.True.cplex.300.log

gap_rel ZeroDivisionError

My team has run into an issue with this package when our objective value is zero. It seems like in your code you have a calculation that doesn't allow the objective value to be zero because it causes a "ZeroDivisionError". Why is that? See attached picture for context.
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.