C++ Logo

sg19

Advanced search

[isocpp-sg19] Graph algorithms -- feedback on the specification of the algorithms

From: Andrzej Krzemienski <akrzemi1_at_[hidden]>
Date: Fri, 9 May 2025 10:35:52 +0200
Hi All,
I am new to this group, so I do not know how such feedback should be
delivered. I didn't have time to report the issue in yesterday's call, so
let me do it over email.

I think that it is a design question how the graph algorithms should
respond to the "questionable" input values, such as non-existent vertex
index, or not properly initialized function output parameters.

Take for instance `dijkstra_shortest_paths` specified in wg21.link/p3128.
It specifies:

1 Mandates:
—(1.1) 0 <= source < num_vertices(graph) for the single-source version.
—(1.2) 0 <= source < num_vertices(graph), for each source in sources, for
the multi-source version.
—(1.3) The weight function w must return a non-negative value.

2 Preconditions:
—(2.1) distances[i] = shortest_path_infinite_distance() for 0 <= i <
num_vertices(g).
—(2.2) predecessors[i] = i for 0 <= i < num_vertices(g).

4 Throws:
—(4.1) An out_of_range exception is thrown in the following cases:
—(4.1.1) size(distances)< size(vertices(g))
—(4.1.2) size(predecessor)< size(vertices(g))
—(4.1.3) source is not in the range 0 <= source < num_vertices(graph).
—(4.1.4) The weight function returns a negative value. This check is not
made if the weight value type is an unsigned integral type.

First of all, section "Mandates" only specifies compile-time checkable
properties, and puts a hard requirement on the implementations to check the
indicated conditions *at compile time*, for instance by using
static_assert. The current conditions 1.1, 1.2, 1.3 are clearly not
compile-time-checkable, so this is a bug in specification.

But more importantly, regarding the condition `0 <= source <
num_vertices(graph)` you have to make the choice:
1. Are the implementations *required* to check the condition and throw an
exception when it is not met, so that the programmers can rely on this
exception, and can "safely" pass bad indexes and expect predictable
behavior?
2. Or are the implementations free to assume that the users always pass the
correct values of `source`? This means that they can check the condition,
but do not have to. If they check, they can either throw an exception, or
launch a debugger, or terminate the program with a core dump. If the
programmer passes the bad value of `source` they are guaranteed nothing,
and it can even be undefined behavior.

It is important that the paper documents this choice and the rationale for
it. It is an important design decision. And then based on this decision,
you either list the conditions under section "Preconditions" or you don't.
If you list this under section "Precondition" it means #2 above, and you
can no longer say that an exception is thrown in this case.

The following links describe what Mandates and Precoonditions mean in
detail:
* https://eel.is/c++draft/description#structure.specifications-3.2
* https://eel.is/c++draft/description#structure.specifications-3.3

I recorded this issue in https://github.com/stdgraph/P1709/issues/113

Regards,
&rzej;

Received on 2025-05-09 08:36:04