Skip to content

Old API for Developers

This API still exists, but I don’t think they were used publicly anywhere. The new API should be preferred.

Entry point

Main file for perprof.

Functions

perprof.main.main()

Entry point when calling perprof.

Source code in perprof/main.py
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
def main():
    """Entry point when calling perprof."""
    try:
        args = set_arguments(sys.argv[1:])

        parser_options, profiler_options = process_arguments(args)

        if args.bokeh:
            # bokeh
            from . import bokeh

            data = bokeh.Profiler(parser_options, profiler_options)
            data.plot()
        elif args.mp:
            # matplotlib
            from . import matplotlib

            data = matplotlib.Profiler(parser_options, profiler_options)
            data.plot()
        elif args.tikz:
            if profiler_options["output_format"] == "pdf" and args.output is None:
                print(
                    _(
                        "ERROR: When using PDF output, you need to provide "
                        "the name of the output file."
                    )
                )
            else:
                # tikz
                from . import tikz

                data = tikz.Profiler(parser_options, profiler_options)
                data.plot()
        elif args.raw:
            # raw
            from . import prof

            print("raw")

            print(prof.Pdata(parser_options, profiler_options))
        elif args.table:
            # table
            from . import prof

            data = prof.Pdata(parser_options, profiler_options)
            data.print_rob_eff_table()
    except ValueError as error:
        print(error)
    except NotImplementedError as error:
        print(error)

perprof.main.process_arguments(args)

Generate the dictionaries with options.

Source code in perprof/main.py
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
def process_arguments(args):
    """Generate the dictionaries with options."""
    parser_options = {
        "free_format": args.free_format,
        "files": args.file_name,
        "success": args.success.split(","),
        "maxtime": args.maxtime,
        "mintime": args.mintime,
        "compare": args.compare,
        "unc": args.unconstrained,
        "infeas_tol": args.infeasibility_tolerance,
    }

    profiler_options = {
        "lang": args.lang,
        "cache": args.cache,
        "files": args.file_name,
        "force": args.force,
        "standalone": args.standalone,
        "semilog": args.semilog,
        "black_and_white": args.black_and_white,
        "output": args.output,
        "pgfplot_version": args.pgfplotcompat,
        "tau": args.tau,
        "pdf_verbose": args.pdf_verbose,
        "title": args.title,
        "xlabel": args.xlabel,
        "ylabel": args.ylabel,
    }

    if args.no_title:
        profiler_options["title"] = None

    if args.background is None:
        profiler_options["background"] = None
    else:
        # Set a tuple of integer
        profiler_options["background"] = tuple(
            int(i) for i in args.background.split(",")
        )
        assert len(profiler_options["background"]) == 3, _(
            "RGB for background must have 3 integers"
        )
    if args.page_background is None:
        profiler_options["page_background"] = None
    else:
        profiler_options["page_background"] = tuple(
            int(i) for i in args.page_background.split(",")
        )
        assert len(profiler_options["page_background"]) == 3, _(
            "RGB for page background must have 3 integers"
        )

    if args.html:
        profiler_options["output_format"] = "html"
    elif args.eps:
        profiler_options["output_format"] = "eps"
    elif args.pdf:
        profiler_options["output_format"] = "pdf"
    elif args.png:
        profiler_options["output_format"] = "png"
    elif args.ps:
        profiler_options["output_format"] = "ps"
    elif args.svg:
        profiler_options["output_format"] = "svg"
    elif args.tex:
        profiler_options["output_format"] = "tex"
    elif args.bokeh:
        profiler_options["output_format"] = "html"
    elif args.mp:
        profiler_options["output_format"] = "png"
    elif args.tikz:
        profiler_options["output_format"] = "pdf"
    else:
        profiler_options["output_format"] = None

    if args.bokeh and profiler_options["output_format"] not in SUPPORT_BOKEH:
        raise NotImplementedError(
            _("Output option {} not supported by bokeh").format(
                profiler_options["output_format"].upper()
            )
        )
    if args.mp and profiler_options["output_format"] not in SUPPORT_MP:
        raise NotImplementedError(
            _("Output option {} not supported by matplotlib").format(
                profiler_options["output_format"].upper()
            )
        )
    if args.tikz and profiler_options["output_format"] not in SUPPORT_TIKZ:
        raise NotImplementedError(
            _("Output option {} not supported by TikZ").format(
                profiler_options["output_format"].upper()
            )
        )
    if args.raw and profiler_options["output_format"]:
        raise NotImplementedError(
            _("--raw does not support output except standard output")
        )
    if args.table and profiler_options["output_format"]:
        raise NotImplementedError(_("--table only write to .tex or to standard output"))

    if args.subset:
        with open(args.subset, encoding="utf-8") as subset_file:
            parser_options["subset"] = [line.strip() for line in subset_file]
        if len(parser_options["subset"]) == 0:
            raise AttributeError(_("ERROR: Subset is empty"))
    else:
        parser_options["subset"] = []

    return parser_options, profiler_options

perprof.main.set_arguments(args)

Set all the arguments of perprof.

Source code in perprof/main.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
def set_arguments(args):
    """Set all the arguments of perprof."""
    import argparse

    parser = argparse.ArgumentParser(
        description=_(
            "A python module for performance profiling "
            "(as described by Dolan and Moré)."
        ),
        fromfile_prefix_chars="@",
    )

    backend_args = parser.add_argument_group(_("Backend options"))
    backend = backend_args.add_mutually_exclusive_group(required=True)
    backend.add_argument(
        "--bokeh",
        action="store_true",
        help=_("Use bokeh as backend for the plot. Default output: HTML"),
    )
    backend.add_argument(
        "--mp",
        action="store_true",
        help=_("Use matplotlib as backend for the plot. Default output: PNG"),
    )
    backend.add_argument(
        "--tikz",
        action="store_true",
        help=_("Use LaTex/TikZ/pgfplots as backend for the plot. Default output: PDF"),
    )
    backend.add_argument(
        "--raw",
        action="store_true",
        help=_("Print raw data. Default output: standard output"),
    )
    backend.add_argument(
        "--table",
        action="store_true",
        help=_("Print table of robustness and efficiency"),
    )

    output_format_args = parser.add_argument_group(_("Output formats"))
    output_format = output_format_args.add_mutually_exclusive_group()
    output_format.add_argument(
        "--html", action="store_true", help=_("The output file will be a HTML file")
    )
    output_format.add_argument(
        "--eps", action="store_true", help=_("The output file will be a EPS file")
    )
    output_format.add_argument(
        "--pdf", action="store_true", help=_("The output file will be a PDF file")
    )
    output_format.add_argument(
        "--png", action="store_true", help=_("The output file will be a PNG file")
    )
    output_format.add_argument(
        "--ps", action="store_true", help=_("The output file will be a PS file")
    )
    output_format.add_argument(
        "--svg", action="store_true", help=_("The output file will be a SVG file")
    )
    output_format.add_argument(
        "--tex", action="store_true", help=_("The output file will be a (La)TeX file")
    )

    tikz_options = parser.add_argument_group(_("TikZ options"))
    tikz_options.add_argument(
        "--standalone",
        action="store_true",
        help=_(
            "Create the header as a standalone to the tex file, "
            "enabling compilation of the result"
        ),
    )
    tikz_options.add_argument(
        "--pgfplotcompat",
        type=float,
        default=None,
        help=_("Set pgfplots backwards compatibility mode to given version"),
    )

    parser.add_argument(
        "--lang",
        "-l",
        choices=["en", "pt_BR"],
        default="en",
        help=_("Set language for plot"),
    )
    parser.add_argument(
        "--free-format",
        action="store_true",
        help=_("When parsing file handle all non `c` character as `d`"),
    )
    parser.add_argument(
        "--pdf-verbose", action="store_true", help=_("Print output of pdflatex")
    )
    parser.add_argument(
        "--black-and-white", action="store_true", help=_("Use only black color.")
    )
    parser.add_argument(
        "--background",
        help=_(
            "RGB values separated by commas for the background color "
            "of the plot. (Values in the 0,255 range)"
        ),
    )
    parser.add_argument(
        "--page-background",
        help=_(
            "RGB values separated by commas for the background color "
            "of the page. (Values in the 0,255 range)"
        ),
    )
    parser.add_argument(
        "--semilog",
        action="store_true",
        help=_("Use logarithmic scale for the x axis of the plot"),
    )
    parser.add_argument(
        "--success",
        type=str,
        default="c",
        help=_(
            "Flags that are interpreted as success, "
            "separated by commas.  Default: `c`"
        ),
    )
    parser.add_argument(
        "--maxtime",
        type=float,
        default=float("inf"),
        help=_(
            "Sets a maximum time for a solved problem. Any problem with a "
            "time greater than this will be considered failed."
        ),
    )
    parser.add_argument(
        "--mintime",
        type=float,
        default=0,
        help=_(
            "Sets a minimum time for a solved problem. Any problem with a "
            "time smaller than this will have the time set to this."
        ),
    )
    parser.add_argument(
        "--compare",
        choices=["exitflag", "optimalvalues"],
        default="exitflag",
        help=_("Choose the type of comparison to be made."),
    )
    parser.add_argument(
        "--unconstrained",
        action="store_true",
        help=_(
            "Set the problems to unconstrained, which implies that there "
            "is no primal feasibility to check."
        ),
    )
    parser.add_argument(
        "--infeasibility-tolerance",
        type=float,
        default=1e-4,
        help=_("Tolerance for the primal and dual infeasibilities"),
    )
    parser.add_argument(
        "--title",
        type=str,
        default=_("Performance Profile"),
        help=_("Set the title to be show on top of the performance profile"),
    )
    parser.add_argument("--no-title", action="store_true", help=_("Removes title"))
    parser.add_argument(
        "--xlabel",
        type=str,
        default=_("Performance ratio"),
        help=_("Set the x label of the performance profile"),
    )
    parser.add_argument(
        "--ylabel",
        type=str,
        default=_("Percentage of problems solved"),
        help=_("Set the y label of the performance profile"),
    )

    parser.add_argument("-c", "--cache", action="store_true", help=_("Enable cache."))
    parser.add_argument(
        "-s", "--subset", help=_("Name of a file with a subset of problems to compare")
    )
    parser.add_argument(
        "--tau", type=float, help=_("Limit the x-axis based this value")
    )
    parser.add_argument(
        "-f", "--force", action="store_true", help=_("Force overwrite the output file")
    )
    parser.add_argument(
        "-o",
        "--output",
        help=_("Name of the file to use as output (the correct extension will be add)"),
    )

    parser.add_argument(
        "--demo", action="store_true", help=_("Use examples files as input")
    )
    parser.add_argument(
        "file_name",
        nargs="*",
        help=_(
            "The name of the files to be used for "
            "the performance profiling (for demo use `--demo`)"
        ),
    )

    parsed_args = parser.parse_args(args)

    # Set input files for demo
    if parsed_args.demo:
        if parsed_args.file_name:
            warnings.warn(_("Using demo mode. Ignoring input files."), UserWarning)
        parsed_args.file_name = [
            os.path.join(THIS_DIR, "examples/alpha.table"),
            os.path.join(THIS_DIR, "examples/beta.table"),
            os.path.join(THIS_DIR, "examples/gamma.table"),
        ]
    elif len(parsed_args.file_name) <= 1:
        raise ValueError(_("You must provide at least two input files."))

    return parsed_args

File parse

Functions to parse the files.

The files must be in the following format::

---
<Metadata 01>: <Value 01>
<Metadata 02>: <Value 02>
---
<Problem Name 01> <Exit Flag 01> <Cost 01>
<Problem Name 02> <Exit Flag 02> <Cost 02>
<Problem Name 03> <Exit Flag 03> <Cost 03>
...

Functions

perprof.parse.parse_file(filename, parser_options)

Parse one file.

Parameters:

  • filename (str) –

    name of the file to be parser

  • parser_options (dict) –

    dictionary with the following keys:

    • subset (list): list with the name of the problems to use
    • success (list): list with strings to mark sucess
    • mintime (float): minimum time running the solver
    • maxtime (float): maximum time running the solver
  • bool (free_format) –

    if False request that fail be mark with d

Returns:

  • data( dict ) –

    performance profile data

  • algname( str ) –

    name of the solver

Source code in perprof/parse.py
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
def parse_file(filename, parser_options):
    """
    Parse one file.

    Args:
        filename (str): name of the file to be parser
        parser_options (dict):
            dictionary with the following keys:

            - subset (list): list with the name of the problems to use
            - success (list): list with strings to mark sucess
            - mintime (float): minimum time running the solver
            - maxtime (float): maximum time running the solver
        bool free_format: if False request that fail be mark with ``d``

    Returns:
        data (dict): performance profile data
        algname (str): name of the solver
    """
    options = parser_options.copy()
    options["algname"] = _str_sanitize(filename)
    colopts = ["name", "exit", "time", "fval", "primal", "dual"]
    col = {}
    for colopt in colopts:
        # Columns starts at 1 but indexing at 0
        options["col_" + colopt] = colopts.index(colopt) + 1
        col[colopt] = colopts.index(colopt)
    data = {}
    with open(filename, encoding="utf-8") as file_:
        line_number = 0
        in_yaml = False
        yaml_header = ""
        for line in file_:
            line_number += 1
            ldata = line.split()
            if len(ldata) == 0:
                continue  # Empty line
            # This is for backward compatibility
            if ldata[0] == "#Name" and len(ldata) >= 2:
                options["algname"] = _str_sanitize(ldata[1])
            # Handle YAML
            elif ldata[0] == "---":
                if in_yaml:
                    _parse_yaml(options, yaml_header)
                    for colopt in colopts:
                        # Columns starts at 1 but indexing at 0
                        col[colopt] = options["col_" + colopt] - 1
                    in_yaml = False
                else:
                    in_yaml = True
            elif in_yaml:
                yaml_header += line
            # Parse data
            elif len(ldata) < 2:
                raise ValueError(
                    _error_message(
                        filename,
                        line_number,
                        _("This line must have at least 2 elements."),
                    )
                )
            else:
                ldata[col["name"]] = _str_sanitize(ldata[col["name"]])
                pname = ldata[col["name"]]
                if options["subset"] and pname not in options["subset"]:
                    continue
                if pname in data:
                    raise ValueError(
                        _error_message(
                            filename,
                            line_number,
                            _("Duplicated problem: ") + pname + ".",
                        )
                    )
                try:
                    time = float(ldata[col["time"]])
                except Exception as exc:
                    raise ValueError(
                        _error_message(
                            filename,
                            line_number,
                            _("Problem has no time/cost: ") + pname + ".",
                        )
                    ) from exc
                if time < options["mintime"]:
                    time = options["mintime"]
                if time >= options["maxtime"]:
                    continue
                if parser_options["compare"] == "optimalvalues":
                    try:
                        if parser_options["unc"]:
                            primal = 0.0
                        else:
                            primal = float(ldata[col["primal"]])
                        dual = float(ldata[col["dual"]])
                    except Exception as exc:
                        raise ValueError(
                            _error_message(
                                filename,
                                line_number,
                                _("Column for primal or dual is out of bounds"),
                            )
                        ) from exc
                    if max(primal, dual) > parser_options["infeas_tol"]:
                        continue
                    data[pname] = {"time": time, "fval": float("inf")}
                    try:
                        data[pname]["fval"] = float(ldata[col["fval"]])
                    except Exception as exc:
                        raise ValueError(
                            _error_message(
                                filename,
                                line_number,
                                _("Column for fval is out of bounds"),
                            )
                        ) from exc
                elif parser_options["compare"] == "exitflag":
                    if time == 0:
                        raise ValueError(
                            _error_message(
                                filename, line_number, _("Time spending can't be zero.")
                            )
                        )
                    if ldata[col["exit"]] in options["success"]:
                        if len(ldata) < 3:
                            raise ValueError(
                                _error_message(
                                    filename,
                                    line_number,
                                    _("This line must have at least 3 elements."),
                                )
                            )
                        data[pname] = {"time": time, "fval": float("inf")}
                    elif options["free_format"] or ldata[col["exit"]] == "d":
                        data[pname] = {"time": float("inf"), "fval": float("inf")}
                    else:
                        raise ValueError(
                            _error_message(
                                filename,
                                line_number,
                                _(
                                    "The second element in this lime must be {} or d."
                                ).format(", ".join(options["success"])),
                            )
                        )
                else:
                    raise KeyError(
                        _(
                            "The parser option 'compare' should be "
                            "'exitflag' or 'optimalvalues'"
                        )
                    )

    if not data:
        raise ValueError(
            _("ERROR: List of problems (intersected with subset, if any) is empty")
        )
    return data, options["algname"]

Profile interface

The functions related with the perform (not the output).

Classes

perprof.prof.Pdata

Store data for performance profile.

Source code in perprof/prof.py
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
class Pdata:
    """Store data for performance profile."""

    def __init__(self, parser_options, profiler_options):
        """Initialize Pdata.

        Args:
            parser_options (dict): parser configuration.
            profiler_options (dict): profiler configuration
        """
        self.data = load_data(parser_options)
        self.cache = profiler_options["cache"]
        self.force = profiler_options["force"]
        self.semilog = profiler_options["semilog"]
        self.black_and_white = profiler_options["black_and_white"]
        self.background = profiler_options["background"]
        self.page_background = profiler_options["page_background"]
        self.pdf_verbose = profiler_options["pdf_verbose"]
        self.output_format = profiler_options["output_format"]
        self.pgfplot_version = profiler_options["pgfplot_version"]
        self.tau = profiler_options["tau"]
        self.title = profiler_options["title"]
        self.xlabel = profiler_options["xlabel"]
        self.ylabel = profiler_options["ylabel"]
        self.already_scaled = False
        self.tablename = profiler_options["output"]

        self.solvers = sorted(list(self.data.keys()))
        self.problems = {x for v in self.data.values() for x in v}
        self.number_problems = len(self.problems)

    def __repr__(self):
        """Return a representation of the Pdata object."""
        str2output = " " * 18

        for solver in self.solvers:
            str2output += f"{solver[-16:]:>16}  "
        str2output += "\n"

        for problem in self.problems:
            str2output += f"{problem:>16}  "
            for solver in self.solvers:
                try:
                    str2output += " " * 8 + f'{self.data[solver][problem]["time"]:8.4} '
                except KeyError:
                    str2output += " " * 13 + "inf  "
            str2output += "\n"

        return str2output[:-2]

    def get_set_solvers(self):
        """
        Get the set of solvers to use.

        Returns:
            solvers (list[dict]): list of solvers
        """
        return self.solvers

    def get_set_problems(self):
        """
        Get the set of problems to use.

        Returns:
            problems (list[str]): list of problems
        """
        return self.problems

    def scale(self):
        """Scale time."""
        times_set = set()
        for problem in self.problems:
            for solver in self.solvers:
                try:
                    self.data[solver][problem]["time"]
                except (KeyError, TypeError):
                    self.data[solver][problem] = {
                        "time": float("inf"),
                        "fval": float("inf"),
                    }

            min_fval = min(v[problem]["fval"] for v in self.data.values())
            if min_fval < float("inf"):
                min_time = min(
                    v[problem]["time"]
                    for v in self.data.values()
                    if v[problem]["fval"] < min_fval + abs(min_fval) * 1e-3 + 1e-6
                )
            else:
                min_time = min(v[problem]["time"] for v in self.data.values())

            for solver in self.solvers:
                try:
                    self.data[solver][problem]["time"] = (
                        self.data[solver][problem]["time"] / min_time
                    )
                except ZeroDivisionError:
                    self.data[solver][problem] = {"time": float("inf")}
                if self.data[solver][problem]["time"] < float("inf"):
                    times_set.add(self.data[solver][problem]["time"])
        if not times_set:
            raise ValueError(_("ERROR: problem set is empty"))

        self.times = sorted(times_set)
        maxt = self.times[-1]
        self.times.append(maxt * 1.05)

        self.already_scaled = True

    def set_percent_problems_solved_by_time(self):
        """Set the percent of problems solved by time."""
        # ppsbt = Percent Problems Solved By Time
        self.ppsbt = {}
        for solver in self.solvers:
            self.ppsbt[solver] = []
            for time in self.times:
                aux = 0
                for problem in self.problems:
                    if time >= self.data[solver][problem]["time"]:
                        aux += 1
                self.ppsbt[solver].append(aux / self.number_problems)
            if self.ppsbt[solver][-1] == 0:
                raise ValueError(
                    _("ERROR:")
                    + solver
                    + _(" has no solved problems. Verify the 'success' flag.")
                )

    def pre_plot(self):
        """Run plot-related checks and processing."""
        if self.force and self.output != sys.stdout and os.path.exists(self.output):
            raise ValueError(
                _("ERROR: File {} exists.\nUse `-f` to overwrite").format(self.output)
            )

        if not self.already_scaled:
            self.scale()

        try:
            self.ppsbt
        except AttributeError:
            self.set_percent_problems_solved_by_time()

    def plot(self):
        """Generate the plot."""
        raise NotImplementedError()

    def print_rob_eff_table(self):
        """Print table of robustness and efficiency."""
        if not self.already_scaled:
            self.scale()

        try:
            self.ppsbt
        except AttributeError:
            self.set_percent_problems_solved_by_time()

        if self.tablename is None:
            output = sys.stdout
            print("Solvers    | Robust  | Effic")
            for solver in self.solvers:
                robustness = round(100 * self.ppsbt[solver][-1], 3)
                efficiency = round(100 * self.ppsbt[solver][0], 3)
                print(f"{solver:10} | {robustness:6.3f}% | {efficiency:6.3f}%")
        else:
            output = f"{self.tablename}.tex"
            output = os.path.abspath(output)

            str2output = [
                "\\begin{tabular}{|c|r|r|} \\hline",
                "Solver & Robustness & Efficiency \\\\ \\hline",
            ]
            for solver in self.solvers:
                robustness = round(100 * self.ppsbt[solver][-1], 3)
                efficiency = round(100 * self.ppsbt[solver][0], 3)
                str2output.append(
                    f"{solver} & {robustness} \\% & {efficiency} \\% \\\\ \\hline"
                )
            str2output.append("\\end{tabular}")

            with open(output, "w", encoding="utf-8") as file_:
                file_.write("\n".join(str2output))
Functions
__init__(parser_options, profiler_options)

Parameters:

  • parser_options (dict) –

    parser configuration.

  • profiler_options (dict) –

    profiler configuration

Source code in perprof/prof.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def __init__(self, parser_options, profiler_options):
    """Initialize Pdata.

    Args:
        parser_options (dict): parser configuration.
        profiler_options (dict): profiler configuration
    """
    self.data = load_data(parser_options)
    self.cache = profiler_options["cache"]
    self.force = profiler_options["force"]
    self.semilog = profiler_options["semilog"]
    self.black_and_white = profiler_options["black_and_white"]
    self.background = profiler_options["background"]
    self.page_background = profiler_options["page_background"]
    self.pdf_verbose = profiler_options["pdf_verbose"]
    self.output_format = profiler_options["output_format"]
    self.pgfplot_version = profiler_options["pgfplot_version"]
    self.tau = profiler_options["tau"]
    self.title = profiler_options["title"]
    self.xlabel = profiler_options["xlabel"]
    self.ylabel = profiler_options["ylabel"]
    self.already_scaled = False
    self.tablename = profiler_options["output"]

    self.solvers = sorted(list(self.data.keys()))
    self.problems = {x for v in self.data.values() for x in v}
    self.number_problems = len(self.problems)
__repr__()

Return a representation of the Pdata object.

Source code in perprof/prof.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def __repr__(self):
    """Return a representation of the Pdata object."""
    str2output = " " * 18

    for solver in self.solvers:
        str2output += f"{solver[-16:]:>16}  "
    str2output += "\n"

    for problem in self.problems:
        str2output += f"{problem:>16}  "
        for solver in self.solvers:
            try:
                str2output += " " * 8 + f'{self.data[solver][problem]["time"]:8.4} '
            except KeyError:
                str2output += " " * 13 + "inf  "
        str2output += "\n"

    return str2output[:-2]
get_set_problems()

Get the set of problems to use.

Returns:

  • problems( list[str] ) –

    list of problems

Source code in perprof/prof.py
87
88
89
90
91
92
93
94
def get_set_problems(self):
    """
    Get the set of problems to use.

    Returns:
        problems (list[str]): list of problems
    """
    return self.problems
get_set_solvers()

Get the set of solvers to use.

Returns:

  • solvers( list[dict] ) –

    list of solvers

Source code in perprof/prof.py
78
79
80
81
82
83
84
85
def get_set_solvers(self):
    """
    Get the set of solvers to use.

    Returns:
        solvers (list[dict]): list of solvers
    """
    return self.solvers
plot()

Generate the plot.

Source code in perprof/prof.py
171
172
173
def plot(self):
    """Generate the plot."""
    raise NotImplementedError()
pre_plot()

Run plot-related checks and processing.

Source code in perprof/prof.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
def pre_plot(self):
    """Run plot-related checks and processing."""
    if self.force and self.output != sys.stdout and os.path.exists(self.output):
        raise ValueError(
            _("ERROR: File {} exists.\nUse `-f` to overwrite").format(self.output)
        )

    if not self.already_scaled:
        self.scale()

    try:
        self.ppsbt
    except AttributeError:
        self.set_percent_problems_solved_by_time()
print_rob_eff_table()

Print table of robustness and efficiency.

Source code in perprof/prof.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def print_rob_eff_table(self):
    """Print table of robustness and efficiency."""
    if not self.already_scaled:
        self.scale()

    try:
        self.ppsbt
    except AttributeError:
        self.set_percent_problems_solved_by_time()

    if self.tablename is None:
        output = sys.stdout
        print("Solvers    | Robust  | Effic")
        for solver in self.solvers:
            robustness = round(100 * self.ppsbt[solver][-1], 3)
            efficiency = round(100 * self.ppsbt[solver][0], 3)
            print(f"{solver:10} | {robustness:6.3f}% | {efficiency:6.3f}%")
    else:
        output = f"{self.tablename}.tex"
        output = os.path.abspath(output)

        str2output = [
            "\\begin{tabular}{|c|r|r|} \\hline",
            "Solver & Robustness & Efficiency \\\\ \\hline",
        ]
        for solver in self.solvers:
            robustness = round(100 * self.ppsbt[solver][-1], 3)
            efficiency = round(100 * self.ppsbt[solver][0], 3)
            str2output.append(
                f"{solver} & {robustness} \\% & {efficiency} \\% \\\\ \\hline"
            )
        str2output.append("\\end{tabular}")

        with open(output, "w", encoding="utf-8") as file_:
            file_.write("\n".join(str2output))
scale()

Scale time.

Source code in perprof/prof.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def scale(self):
    """Scale time."""
    times_set = set()
    for problem in self.problems:
        for solver in self.solvers:
            try:
                self.data[solver][problem]["time"]
            except (KeyError, TypeError):
                self.data[solver][problem] = {
                    "time": float("inf"),
                    "fval": float("inf"),
                }

        min_fval = min(v[problem]["fval"] for v in self.data.values())
        if min_fval < float("inf"):
            min_time = min(
                v[problem]["time"]
                for v in self.data.values()
                if v[problem]["fval"] < min_fval + abs(min_fval) * 1e-3 + 1e-6
            )
        else:
            min_time = min(v[problem]["time"] for v in self.data.values())

        for solver in self.solvers:
            try:
                self.data[solver][problem]["time"] = (
                    self.data[solver][problem]["time"] / min_time
                )
            except ZeroDivisionError:
                self.data[solver][problem] = {"time": float("inf")}
            if self.data[solver][problem]["time"] < float("inf"):
                times_set.add(self.data[solver][problem]["time"])
    if not times_set:
        raise ValueError(_("ERROR: problem set is empty"))

    self.times = sorted(times_set)
    maxt = self.times[-1]
    self.times.append(maxt * 1.05)

    self.already_scaled = True
set_percent_problems_solved_by_time()

Set the percent of problems solved by time.

Source code in perprof/prof.py
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def set_percent_problems_solved_by_time(self):
    """Set the percent of problems solved by time."""
    # ppsbt = Percent Problems Solved By Time
    self.ppsbt = {}
    for solver in self.solvers:
        self.ppsbt[solver] = []
        for time in self.times:
            aux = 0
            for problem in self.problems:
                if time >= self.data[solver][problem]["time"]:
                    aux += 1
            self.ppsbt[solver].append(aux / self.number_problems)
        if self.ppsbt[solver][-1] == 0:
            raise ValueError(
                _("ERROR:")
                + solver
                + _(" has no solved problems. Verify the 'success' flag.")
            )

Functions

perprof.prof.load_data(parser_options)

Load the data.

Parameters:

  • parser_options (dict) –

    the configuration dicionary

Source code in perprof/prof.py
14
15
16
17
18
19
20
21
22
23
24
25
def load_data(parser_options):
    """
    Load the data.

    Args:
        parser_options (dict): the configuration dicionary
    """
    data = {}
    for file_ in parser_options["files"]:
        data_tmp, solver_name = parse.parse_file(file_, parser_options)
        data[solver_name] = data_tmp
    return data

Profiler using TikZ

Plot using tikz.

Classes

perprof.tikz.Profiler

Bases: prof.Pdata

The profiler using TikZ.

Source code in perprof/tikz.py
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
class Profiler(prof.Pdata):
    """The profiler using TikZ."""

    def __init__(self, parser_options, profiler_options):
        """Initialize Profiler with TikZ.

        Args:
            parser_options (dict): parser options.
            profiler_options (dict): profiler options
        """
        if profiler_options["output"] is None:
            self.output = sys.stdout
        else:
            self.output = f'{profiler_options["output"]}.tex'
            self.output = os.path.abspath(self.output)
        self.standalone = profiler_options["standalone"]
        self.output_format = profiler_options["output_format"]

        # Language for the plot
        translation = gettext.translation(
            "perprof", os.path.join(THIS_DIR, "locale"), [profiler_options["lang"]]
        )
        self.plot_lang = translation.gettext

        prof.Pdata.__init__(self, parser_options, profiler_options)

    # pylint: disable=too-many-locals,too-many-branches,too-many-statements
    def plot(self):
        """Create the performance profile using TikZ/PgfPlots."""
        self.pre_plot()

        if self.black_and_white and len(self.solvers) > 13:
            raise ValueError(
                _("ERROR: Maximum numbers of solvers in black and white plot is 13.")
            )
        if not self.black_and_white and len(self.solvers) > 30:
            raise ValueError(
                _("ERROR: Maximum numbers of solvers in color plot is 30.")
            )

        maxt = max(self.times)
        try:
            maxt = min(maxt, self.tau)
        except (AttributeError, TypeError):
            self.tau = maxt

        str2output = []

        if self.standalone or self.output_format == "pdf":
            str2output.append("\\documentclass{standalone}")
            str2output.append("\\usepackage[utf8]{inputenc}")
            str2output.append("\\usepackage[T1]{fontenc}")
            str2output.append("\\usepackage{tikz}")
            str2output.append("\\usepackage{pgfplots}")
            if self.pgfplot_version is not None:
                str2output.append(f"\\pgfplotsset{{compat={self.pgfplot_version}}}")
            else:
                str2output.append(
                    "\\pgfplotsset{compat=newest,compat/show "
                    "suggested version=false}"
                )
            if self.page_background:
                str2output.append(
                    "\\definecolor{pagebg}{RGB}{"
                    + ",".join(str(x) for x in self.page_background)
                    + "}"
                )
                str2output.append("\\pagecolor{pagebg}")
            str2output.append("\\begin{document}")
        else:
            str2output.append("\\begin{center}")
        str2output.append("\\begin{tikzpicture}")

        if self.semilog:
            str2output.append("  \\begin{semilogxaxis}[const plot,")
        else:
            str2output.append("  \\begin{axis}[const plot,")
        if self.black_and_white:
            lines = ["dashed", "dotted", "dashdotted", "dashdotdotted"]
            types = ["", "loosely ", "densely "]
            str2output.append("  cycle list={")
            aux = ["solid"]
            for k in range(0, len(self.solvers)):
                i = k % len(lines)
                j = k // len(lines)
                aux.append(f"  {{{types[j]}{lines[i]}}}")
            str2output.append(",\n".join(aux) + "},")
        else:
            colors = [
                "blue",
                "red",
                "black",
                "brown",
                "green!80!black",
                "magenta!80!black",
            ]
            lines = ["solid", "dashed", "dotted", "dashdotted", "dashdotdotted"]
            str2output.append("  cycle list={")
            aux = []
            for k in range(0, len(self.solvers)):
                i = k % len(colors)
                j = k // len(colors)
                aux.append(f"  {{{colors[i]},{lines[j]}}}")
            str2output.append(",\n".join(aux) + "},")
        if self.background:
            red, green, blue = self.background
            str2output.append(
                "axis background/.style="
                f"{{fill={{rgb,255:red,{red};green,{green};blue,{blue}}}}},"
            )
        if len(self.solvers) > 5:
            legend_pos = "outer north east"
        else:
            legend_pos = "south east"
        if self.title is None:
            title = ""
        else:
            title = f"title={{{self.plot_lang(self.title)}}},"

        xlabel = self.plot_lang(self.xlabel)
        ylabel = self.plot_lang(self.ylabel)

        str2output.append(
            f"""xmin=1, xmax={maxt:.2f},
                ymin=-0.003, ymax=1.003,
                ymajorgrids,
                ytick={{0,0.2,0.4,0.6,0.8,1.0}},
                xlabel={{{xlabel}}},
                ylabel={{{ylabel}}},{title}
                legend pos={{{legend_pos}}},
                width=\\textwidth
            ]"""
        )

        for solver in self.solvers:
            this_ppsbt = self.ppsbt[solver]
            str2output.append("  \\addplot+[mark=none, thick] coordinates {")
            str2output.append(f"    ({self.times[0]:.4f},{this_ppsbt[0]:.4f})")
            last_t = round(self.times[0], 4)
            last_p = round(self.ppsbt[solver][0], 4)
            for i in range(1, len(self.times) - 1):
                dx = round(self.times[i], 4) - last_t
                dx2 = round(self.times[i + 1], 4) - last_t
                dy = round(this_ppsbt[i], 4) - last_p
                dy2 = round(this_ppsbt[i + 1], 4) - last_p
                if dx * dy2 == dy * dx2:
                    continue
                if self.times[i] <= self.tau:
                    time = round(self.times[i], 4)
                    ppsbt = round(self.ppsbt[solver][i], 4)
                    str2output.append(f"    ({time:.4f},{ppsbt:.4f})")
                    last_t = time
                    last_p = ppsbt
                else:
                    break
            j = len(self.times) - 1
            str2output.append(f"    ({self.times[j]:.4f},{this_ppsbt[j]:.4f})")
            str2output.append("  };")
            str2output.append(f"  \\addlegendentry{{{solver}}}")

        if self.semilog:
            str2output.append("  \\end{semilogxaxis}")
        else:
            str2output.append("  \\end{axis}")
        str2output.append("\\end{tikzpicture}")
        if self.standalone or self.output_format == "pdf":
            str2output.append("\\end{document}")
        else:
            str2output.append("\\end{center}\n")

        try:
            with open(self.output, "w", encoding="utf-8") as file_:
                file_.write("\n".join(str2output))

            if self.output_format == "pdf":
                if self.pdf_verbose:
                    mode = "nonstopmode"
                else:
                    mode = "batchmode"
                subprocess.check_call(
                    [
                        "pdflatex",
                        "-interaction",
                        mode,
                        "-output-directory",
                        os.path.dirname(self.output),
                        self.output,
                    ]
                )
        except TypeError:
            # When using stdout
            print(str2output, file=self.output)
Functions
__init__(parser_options, profiler_options)

Parameters:

  • parser_options (dict) –

    parser options.

  • profiler_options (dict) –

    profiler options

Source code in perprof/tikz.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
def __init__(self, parser_options, profiler_options):
    """Initialize Profiler with TikZ.

    Args:
        parser_options (dict): parser options.
        profiler_options (dict): profiler options
    """
    if profiler_options["output"] is None:
        self.output = sys.stdout
    else:
        self.output = f'{profiler_options["output"]}.tex'
        self.output = os.path.abspath(self.output)
    self.standalone = profiler_options["standalone"]
    self.output_format = profiler_options["output_format"]

    # Language for the plot
    translation = gettext.translation(
        "perprof", os.path.join(THIS_DIR, "locale"), [profiler_options["lang"]]
    )
    self.plot_lang = translation.gettext

    prof.Pdata.__init__(self, parser_options, profiler_options)
plot()

Create the performance profile using TikZ/PgfPlots.

Source code in perprof/tikz.py
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
def plot(self):
    """Create the performance profile using TikZ/PgfPlots."""
    self.pre_plot()

    if self.black_and_white and len(self.solvers) > 13:
        raise ValueError(
            _("ERROR: Maximum numbers of solvers in black and white plot is 13.")
        )
    if not self.black_and_white and len(self.solvers) > 30:
        raise ValueError(
            _("ERROR: Maximum numbers of solvers in color plot is 30.")
        )

    maxt = max(self.times)
    try:
        maxt = min(maxt, self.tau)
    except (AttributeError, TypeError):
        self.tau = maxt

    str2output = []

    if self.standalone or self.output_format == "pdf":
        str2output.append("\\documentclass{standalone}")
        str2output.append("\\usepackage[utf8]{inputenc}")
        str2output.append("\\usepackage[T1]{fontenc}")
        str2output.append("\\usepackage{tikz}")
        str2output.append("\\usepackage{pgfplots}")
        if self.pgfplot_version is not None:
            str2output.append(f"\\pgfplotsset{{compat={self.pgfplot_version}}}")
        else:
            str2output.append(
                "\\pgfplotsset{compat=newest,compat/show "
                "suggested version=false}"
            )
        if self.page_background:
            str2output.append(
                "\\definecolor{pagebg}{RGB}{"
                + ",".join(str(x) for x in self.page_background)
                + "}"
            )
            str2output.append("\\pagecolor{pagebg}")
        str2output.append("\\begin{document}")
    else:
        str2output.append("\\begin{center}")
    str2output.append("\\begin{tikzpicture}")

    if self.semilog:
        str2output.append("  \\begin{semilogxaxis}[const plot,")
    else:
        str2output.append("  \\begin{axis}[const plot,")
    if self.black_and_white:
        lines = ["dashed", "dotted", "dashdotted", "dashdotdotted"]
        types = ["", "loosely ", "densely "]
        str2output.append("  cycle list={")
        aux = ["solid"]
        for k in range(0, len(self.solvers)):
            i = k % len(lines)
            j = k // len(lines)
            aux.append(f"  {{{types[j]}{lines[i]}}}")
        str2output.append(",\n".join(aux) + "},")
    else:
        colors = [
            "blue",
            "red",
            "black",
            "brown",
            "green!80!black",
            "magenta!80!black",
        ]
        lines = ["solid", "dashed", "dotted", "dashdotted", "dashdotdotted"]
        str2output.append("  cycle list={")
        aux = []
        for k in range(0, len(self.solvers)):
            i = k % len(colors)
            j = k // len(colors)
            aux.append(f"  {{{colors[i]},{lines[j]}}}")
        str2output.append(",\n".join(aux) + "},")
    if self.background:
        red, green, blue = self.background
        str2output.append(
            "axis background/.style="
            f"{{fill={{rgb,255:red,{red};green,{green};blue,{blue}}}}},"
        )
    if len(self.solvers) > 5:
        legend_pos = "outer north east"
    else:
        legend_pos = "south east"
    if self.title is None:
        title = ""
    else:
        title = f"title={{{self.plot_lang(self.title)}}},"

    xlabel = self.plot_lang(self.xlabel)
    ylabel = self.plot_lang(self.ylabel)

    str2output.append(
        f"""xmin=1, xmax={maxt:.2f},
            ymin=-0.003, ymax=1.003,
            ymajorgrids,
            ytick={{0,0.2,0.4,0.6,0.8,1.0}},
            xlabel={{{xlabel}}},
            ylabel={{{ylabel}}},{title}
            legend pos={{{legend_pos}}},
            width=\\textwidth
        ]"""
    )

    for solver in self.solvers:
        this_ppsbt = self.ppsbt[solver]
        str2output.append("  \\addplot+[mark=none, thick] coordinates {")
        str2output.append(f"    ({self.times[0]:.4f},{this_ppsbt[0]:.4f})")
        last_t = round(self.times[0], 4)
        last_p = round(self.ppsbt[solver][0], 4)
        for i in range(1, len(self.times) - 1):
            dx = round(self.times[i], 4) - last_t
            dx2 = round(self.times[i + 1], 4) - last_t
            dy = round(this_ppsbt[i], 4) - last_p
            dy2 = round(this_ppsbt[i + 1], 4) - last_p
            if dx * dy2 == dy * dx2:
                continue
            if self.times[i] <= self.tau:
                time = round(self.times[i], 4)
                ppsbt = round(self.ppsbt[solver][i], 4)
                str2output.append(f"    ({time:.4f},{ppsbt:.4f})")
                last_t = time
                last_p = ppsbt
            else:
                break
        j = len(self.times) - 1
        str2output.append(f"    ({self.times[j]:.4f},{this_ppsbt[j]:.4f})")
        str2output.append("  };")
        str2output.append(f"  \\addlegendentry{{{solver}}}")

    if self.semilog:
        str2output.append("  \\end{semilogxaxis}")
    else:
        str2output.append("  \\end{axis}")
    str2output.append("\\end{tikzpicture}")
    if self.standalone or self.output_format == "pdf":
        str2output.append("\\end{document}")
    else:
        str2output.append("\\end{center}\n")

    try:
        with open(self.output, "w", encoding="utf-8") as file_:
            file_.write("\n".join(str2output))

        if self.output_format == "pdf":
            if self.pdf_verbose:
                mode = "nonstopmode"
            else:
                mode = "batchmode"
            subprocess.check_call(
                [
                    "pdflatex",
                    "-interaction",
                    mode,
                    "-output-directory",
                    os.path.dirname(self.output),
                    self.output,
                ]
            )
    except TypeError:
        # When using stdout
        print(str2output, file=self.output)

Profiler using matplotlib

Plot using matplotlib.

Classes

perprof.matplotlib.Profiler

Bases: prof.Pdata

The profiler using matplotlib.

Source code in perprof/matplotlib.py
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class Profiler(prof.Pdata):
    """The profiler using matplotlib."""

    def __init__(self, parser_options, profiler_options):
        """Intialize Profiler with Matplotlib.

        Args:
            parser_options (dict): parser options.
            profiler_options (dict): profiler options
        """
        if profiler_options["output"] is None:
            self.output = f'performance-profile.{profiler_options["output_format"]}'
        else:
            self.output = (
                f'{profiler_options["output"]}.{profiler_options["output_format"]}'
            )
        self.output_format = profiler_options["output_format"]

        # Language for the plot
        translation = gettext.translation(
            "perprof", os.path.join(THIS_DIR, "locale"), [profiler_options["lang"]]
        )
        self.plot_lang = translation.gettext

        prof.Pdata.__init__(self, parser_options, profiler_options)

    # pylint: disable=too-many-branches
    def plot(self):
        """Create the performance profile using matplotlib."""
        self.pre_plot()

        # Hack need to background color
        figure_ = plt.figure()
        plot_ = figure_.add_subplot(111)

        # Set configurations handle when saving the plot
        save_configs = {
            "format": self.output_format,
        }

        if self.page_background:
            if not self.background:
                self.background = self.page_background
            # RGB tuples must be in the range [0,1]
            save_configs["facecolor"] = (
                self.page_background[0] / 255,
                self.page_background[1] / 255,
                self.page_background[2] / 255,
            )
        if self.background:
            plot_.set_facecolor(
                (
                    self.background[0] / 255,
                    self.background[1] / 255,
                    self.background[2] / 255,
                )
            )
            if not self.page_background:
                figure_.patch.set_alpha(0.0)
        if not self.background and not self.page_background:
            save_configs["transparent"] = True
            save_configs["facecolor"] = "none"

        # Define the linestyles
        if self.black_and_white:
            linestyles = ["k-", "k--", "k:", "k-."]
        else:
            linestyles = ["b", "g", "r", "c", "m", "y"]

        # Generate the plot for each solver
        for idx, solver in enumerate(self.solvers):
            plot_.step(
                self.times,
                self.ppsbt[solver],
                linestyles[idx],
                label=solver,
                where="post",
            )

        # Change the xscale to log scale
        if self.semilog:
            plt.gca().set_xscale("log")

        # Axis
        try:
            maxt = min(max(self.times), self.tau)
        except (AttributeError, TypeError):
            maxt = max(self.times)
        plt.gca().set_xlim(1, maxt)
        plt.gca().set_xlabel(self.plot_lang(self.xlabel))
        plt.gca().set_ylim(-0.002, 1.006)
        plt.gca().set_ylabel(self.plot_lang(self.ylabel))
        if self.title is not None:
            plt.gca().set_title(self.plot_lang(self.title))

        # Legend
        plt.gca().legend(loc=4)

        # Help lines
        plt.gca().grid(axis="y", color="0.5", linestyle="-")

        # Save the plot
        plt.savefig(self.output, bbox_inches="tight", pad_inches=0.05, **save_configs)
Functions
__init__(parser_options, profiler_options)

Parameters:

  • parser_options (dict) –

    parser options.

  • profiler_options (dict) –

    profiler options

Source code in perprof/matplotlib.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def __init__(self, parser_options, profiler_options):
    """Intialize Profiler with Matplotlib.

    Args:
        parser_options (dict): parser options.
        profiler_options (dict): profiler options
    """
    if profiler_options["output"] is None:
        self.output = f'performance-profile.{profiler_options["output_format"]}'
    else:
        self.output = (
            f'{profiler_options["output"]}.{profiler_options["output_format"]}'
        )
    self.output_format = profiler_options["output_format"]

    # Language for the plot
    translation = gettext.translation(
        "perprof", os.path.join(THIS_DIR, "locale"), [profiler_options["lang"]]
    )
    self.plot_lang = translation.gettext

    prof.Pdata.__init__(self, parser_options, profiler_options)
plot()

Create the performance profile using matplotlib.

Source code in perprof/matplotlib.py
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def plot(self):
    """Create the performance profile using matplotlib."""
    self.pre_plot()

    # Hack need to background color
    figure_ = plt.figure()
    plot_ = figure_.add_subplot(111)

    # Set configurations handle when saving the plot
    save_configs = {
        "format": self.output_format,
    }

    if self.page_background:
        if not self.background:
            self.background = self.page_background
        # RGB tuples must be in the range [0,1]
        save_configs["facecolor"] = (
            self.page_background[0] / 255,
            self.page_background[1] / 255,
            self.page_background[2] / 255,
        )
    if self.background:
        plot_.set_facecolor(
            (
                self.background[0] / 255,
                self.background[1] / 255,
                self.background[2] / 255,
            )
        )
        if not self.page_background:
            figure_.patch.set_alpha(0.0)
    if not self.background and not self.page_background:
        save_configs["transparent"] = True
        save_configs["facecolor"] = "none"

    # Define the linestyles
    if self.black_and_white:
        linestyles = ["k-", "k--", "k:", "k-."]
    else:
        linestyles = ["b", "g", "r", "c", "m", "y"]

    # Generate the plot for each solver
    for idx, solver in enumerate(self.solvers):
        plot_.step(
            self.times,
            self.ppsbt[solver],
            linestyles[idx],
            label=solver,
            where="post",
        )

    # Change the xscale to log scale
    if self.semilog:
        plt.gca().set_xscale("log")

    # Axis
    try:
        maxt = min(max(self.times), self.tau)
    except (AttributeError, TypeError):
        maxt = max(self.times)
    plt.gca().set_xlim(1, maxt)
    plt.gca().set_xlabel(self.plot_lang(self.xlabel))
    plt.gca().set_ylim(-0.002, 1.006)
    plt.gca().set_ylabel(self.plot_lang(self.ylabel))
    if self.title is not None:
        plt.gca().set_title(self.plot_lang(self.title))

    # Legend
    plt.gca().legend(loc=4)

    # Help lines
    plt.gca().grid(axis="y", color="0.5", linestyle="-")

    # Save the plot
    plt.savefig(self.output, bbox_inches="tight", pad_inches=0.05, **save_configs)