spot/lbtt/src/StatDisplay.cc
Alexandre Duret-Lutz ababb9ff93 Initial revision
2002-10-01 14:21:01 +00:00

1455 lines
46 KiB
C++

/*
* Copyright (C) 1999, 2000, 2001, 2002
* Heikki Tauriainen <Heikki.Tauriainen@hut.fi>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef __GNUC__
#pragma implementation
#endif /* __GNUC__ */
#include <config.h>
#include <string>
#include "DispUtil.h"
#include "Exception.h"
#include "SharedTestData.h"
#include "StatDisplay.h"
#include "StringUtil.h"
#include "TestRoundInfo.h"
namespace StatDisplay
{
using namespace ::DispUtil;
using namespace ::SharedTestData;
using namespace ::StringUtil;
/* ========================================================================= */
void printBuchiAutomatonStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm,
int result_id)
/* ----------------------------------------------------------------------------
*
* Description: Displays information about a Büchi automaton, extracting the
* information from a TestStatistics structure stored in the
* UserInterface object.
*
* Arguments: stream -- A reference to the output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- Identifier of the algorithm used for
* generating the automaton.
* result_id -- Selects between the automata constructed from
* a formula and its negation.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
const AutomatonStats& automaton_stats =
test_results[algorithm].automaton_stats[result_id];
estream << string(indent, ' ');
if (!automaton_stats.buchiAutomatonComputed())
estream << "not computed";
else
{
estream << "number of states:" + string(6, ' ')
+ toString(automaton_stats.number_of_buchi_states)
+ '\n' + string(indent, ' ') + "number of transitions: "
+ toString(automaton_stats.number_of_buchi_transitions)
+ '\n' + string(indent, ' ') + "acceptance sets:"
+ string(7, ' ')
+ toString(automaton_stats.number_of_acceptance_sets)
+ '\n' + string(indent, ' ') + "computation time:"
+ string(6, ' ');
if (automaton_stats.buchi_generation_time != -1.0)
{
changeStreamFormatting(stream, 9, 2, ios::fixed | ios::left);
estream << automaton_stats.buchi_generation_time;
restoreStreamFormatting(stream);
estream << " seconds (user time)";
}
else
estream << "N/A";
}
estream << '\n';
estream.flush();
}
/* ========================================================================= */
void printProductAutomatonStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm,
int result_id)
/* ----------------------------------------------------------------------------
*
* Description: Displays information about a product automaton, extracting
* the information from a TestStatistics structure stored in the
* UserInterface object.
*
* Arguments: stream -- A reference to the output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- Identifier of the algorithm used for
* generating the product automaton.
* result_id -- Selects between the automata constructed from
* a formula and its negation.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
const AutomatonStats& automaton_stats =
test_results[algorithm].automaton_stats[result_id];
estream << string(indent, ' ');
if (!automaton_stats.productAutomatonComputed())
estream << "not computed";
else
{
estream << "number of states:" + string(6, ' ');
changeStreamFormatting(stream, 9, 0, ios::left);
estream << automaton_stats.number_of_product_states;
restoreStreamFormatting(stream);
estream << " [";
if (automaton_stats.number_of_product_states != 0)
{
changeStreamFormatting(stream, 0, 2, ios::fixed);
estream << static_cast<double>
(automaton_stats.number_of_product_states)
/ static_cast<double>(automaton_stats.number_of_buchi_states)
/ static_cast<double>(round_info.statespace->size())
* 100.0;
restoreStreamFormatting(stream);
estream << "% of worst case ("
<< automaton_stats.number_of_buchi_states
* round_info.statespace->size()
<< ')';
}
else
estream << "empty automaton";
estream << "]\n" + string(indent, ' ') + "number of transitions: "
+ toString(automaton_stats.number_of_product_transitions);
}
estream << '\n';
estream.flush();
}
/* ========================================================================= */
void printAcceptanceCycleStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm,
int result_id)
/* ----------------------------------------------------------------------------
*
* Description: Displays information about the number of system states from
* which begins an execution accepted by a Büchi automaton. The
* information is extracted from a TestStatistics structure
* stored in the UserInterface object.
*
* Arguments: stream -- A reference to the output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- Identifier of the algorithm used for
* computing the Büchi automaton whose accepting
* cycles are to be considered.
* result_id -- Selects between the result computed for a
* formula and its negation.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
const AutomatonStats& automaton_stats =
test_results[algorithm].automaton_stats[result_id];
estream << string(indent, ' ');
if (!automaton_stats.emptiness_check_performed)
estream << "not computed";
else if (configuration.global_options.product_mode == Configuration::LOCAL)
{
estream << string("cycle ");
if (automaton_stats.emptiness_check_result[0])
estream << "reachable ";
else
estream << "not reachable";
estream << " (from the initial state)";
}
else
{
estream << "cycle reachable from ";
changeStreamFormatting(stream, 9, 0, ios::left);
estream << automaton_stats.emptiness_check_result.count();
restoreStreamFormatting(stream);
estream << " states\n" + string(indent, ' ')
+ "not reachable from ";
changeStreamFormatting(stream, 9, 0, ios::left);
estream << (round_info.real_emptiness_check_size
- automaton_stats.emptiness_check_result.count());
restoreStreamFormatting(stream);
estream << " states";
}
estream << '\n';
estream.flush();
}
/* ========================================================================= */
void printConsistencyCheckStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm)
/* ----------------------------------------------------------------------------
*
* Description: Displays information about the consistency check result for
* a given algorithm, extracting the information from a
* TestStatistics structure stored in the UserInterface object.
*
* Arguments: stream -- A reference to an output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- Identifier of the algorithm whose consistency
* check result should be displayed.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
const AlgorithmTestResults& test_result = test_results[algorithm];
estream << string(indent, ' ');
if (test_result.consistency_check_result == -1)
estream << "not performed";
else
{
estream << "result:" + string(18, ' ');
if (test_result.consistency_check_result == 0)
{
estream << "failed ["
+ toString(test_result.failed_consistency_check_comparisons)
+ " (";
changeStreamFormatting(stream, 0, 2, ios::fixed);
estream << ((test_result.consistency_check_comparisons == 0)
? 0.0
: static_cast<double>
(test_result.failed_consistency_check_comparisons)
/ test_result.consistency_check_comparisons * 100.0);
restoreStreamFormatting(stream);
estream << "%) of "
+ toString(test_result.consistency_check_comparisons)
+ " test cases]";
}
else
estream << "passed";
}
estream << '\n';
estream.flush();
}
/* ========================================================================= */
void printCrossComparisonStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm)
/* ----------------------------------------------------------------------------
*
* Description: Displays information about the model checking result cross-
* comparison check, extracting the information from a vector of
* TestStatistics structures stored in the UserInterface object.
*
* Arguments: stream -- A reference to an output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- If less than the number of algorithms, show
* only the results for the algorithm with this
* identifier.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
bool no_errors_to_report = true;
if (algorithm < configuration.algorithms.size()
&& !configuration.algorithms[algorithm].enabled)
{
estream << string(indent, ' ') + "not performed\n\n";
estream.flush();
return;
}
estream << string(indent, ' ') + "result:";
const AutomatonStats* alg_1_pos_results;
const AutomatonStats* alg_1_neg_results;
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
alg_1 = 0;
alg_1 < test_results.size();
alg_1++)
{
alg_1_pos_results = &test_results[alg_1].automaton_stats[0];
alg_1_neg_results = &test_results[alg_1].automaton_stats[1];
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
alg_2 = alg_1 + 1;
alg_2 < test_results.size();
alg_2++)
{
if ((algorithm >= configuration.algorithms.size()
|| alg_1 == algorithm
|| alg_2 == algorithm)
&& configuration.algorithms[alg_1].enabled
&& configuration.algorithms[alg_2].enabled)
{
bool pos_test, neg_test;
for (int counter = 0; counter < 2; counter++)
{
if (counter == 0)
{
pos_test = !alg_1_pos_results->crossComparisonPerformed(alg_2);
neg_test = !alg_1_neg_results->crossComparisonPerformed(alg_2);
}
else
{
pos_test = (alg_1_pos_results->cross_comparison_stats[alg_2].
second > 0);
neg_test = (alg_1_neg_results->cross_comparison_stats[alg_2].
second > 0);
}
if (pos_test || neg_test)
{
estream << '\n' + string(indent + 2, ' ');
no_errors_to_report = false;
estream << string(counter == 0 ? "N/A " : "failed") + " (";
if (pos_test)
estream << string("+") + (neg_test ? "-)" : ") ");
else
estream << "-) ";
estream << ' ';
if (alg_1 == round_info.number_of_translators)
estream << "lbtt";
else
estream << configuration.algorithmString(alg_1);
estream << ", ";
if (alg_2 == round_info.number_of_translators)
estream << "lbtt";
else
estream << configuration.algorithmString(alg_2);
}
}
}
}
}
if (no_errors_to_report)
estream << string(20, ' ') + "no failures detected";
estream << "\n\n";
estream.flush();
}
/* ========================================================================= */
void printBuchiIntersectionCheckStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm)
/* ----------------------------------------------------------------------------
*
* Description: Displays information about the Büchi automaton intersection
* emptiness check results, extracting the information from a
* TestStatistics structure stored in the UserInterface object.
*
* Arguments: stream -- A reference to an output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- If less than the number of algorithms, show
* only the results for the algorithm with this
* identifier.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
bool no_errors_to_report = true;
if (algorithm < round_info.number_of_translators
&& !configuration.algorithms[algorithm].enabled)
{
estream << string(indent, ' ') + "not performed\n\n";
estream.flush();
return;
}
estream << string(indent, ' ') + "result:";
const AutomatonStats* alg_1_pos_results;
const AutomatonStats* alg_1_neg_results;
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
alg_1 = 0;
alg_1 < round_info.number_of_translators;
alg_1++)
{
alg_1_pos_results = &test_results[alg_1].automaton_stats[0];
alg_1_neg_results = &test_results[alg_1].automaton_stats[1];
for (vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
alg_2 = alg_1;
alg_2 < round_info.number_of_translators;
alg_2++)
{
if ((algorithm >= round_info.number_of_translators
|| alg_1 == algorithm
|| alg_2 == algorithm)
&& configuration.algorithms[alg_1].enabled
&& configuration.algorithms[alg_2].enabled)
{
bool pos_test, neg_test;
for (int counter = -1; counter < 1; counter++)
{
pos_test = (alg_1_pos_results->buchi_intersection_check_stats[alg_2]
== counter);
neg_test = (alg_1_neg_results->buchi_intersection_check_stats[alg_2]
== counter);
if (pos_test || neg_test)
{
estream << '\n' + string(indent + 2, ' ');
no_errors_to_report = false;
estream << string(counter == -1 ? "N/A " : "failed") + ' ';
if (alg_1 != alg_2)
{
estream << '(';
if (pos_test)
estream << string("+") + (neg_test ? "-)" : ") ");
else
estream << "-) ";
}
else
estream << " ";
estream << ' ' + configuration.algorithmString(alg_1);
if (alg_1 != alg_2)
{
estream << ", (";
if (pos_test)
estream << string("-") + (neg_test ? "+" : "");
else
estream << '+';
estream << ") " + configuration.algorithmString(alg_2);
}
}
}
}
}
}
if (no_errors_to_report)
estream << string(20, ' ') + "no failures detected";
estream << "\n\n";
estream.flush();
}
/* ========================================================================= */
void printAllStats
(ostream& stream, int indent,
vector<AlgorithmTestResults, ALLOC(AlgorithmTestResults) >::size_type
algorithm)
/* ----------------------------------------------------------------------------
*
* Description: Displays all test information (Büchi automaton and product
* automaton statistics, acceptance cycle information,
* consistency check result) for an algorithm.
*
* Arguments: stream -- A reference to an output stream to which the
* information should be written.
* indent -- Number of spaces to leave on the left of the
* output.
* algorithm -- Identifier of an algorithm.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
estream << string(indent, ' ') + configuration.algorithmString(algorithm)
+ '\n';
estream.flush();
for (int counter = 0; counter < 2; counter++)
{
estream << string(indent + 2, ' ')
+ (counter == 0 ? "Positive" : "Negated") + " formula:\n"
+ string(indent + 4, ' ') + "Büchi automaton:\n";
printBuchiAutomatonStats(stream, indent + 6, algorithm, counter);
if (configuration.global_options.do_comp_test
|| configuration.global_options.do_cons_test)
{
estream << string(indent + 4, ' ') + "Product automaton:\n";
printProductAutomatonStats(stream, indent + 6, algorithm, counter);
estream << string(indent + 4, ' ') + "Accepting cycles:\n";
printAcceptanceCycleStats(stream, indent + 6, algorithm, counter);
}
}
if (configuration.global_options.do_cons_test)
{
estream << string(indent + 2, ' ') + "Result consistency check:\n";
printConsistencyCheckStats(stream, indent + 4, algorithm);
}
estream << '\n';
estream.flush();
}
/* ========================================================================= */
void printCollectiveCrossComparisonStats
(ostream& stream,
vector<TestStatistics, ALLOC(TestStatistics) >::size_type algorithm_y,
vector<TestStatistics, ALLOC(TestStatistics) >::size_type algorithm_x,
int data_type)
/* ----------------------------------------------------------------------------
*
* Description: Called by printCollectiveStats in order to fill a single cell
* of the result cross-comparison table.
*
* Arguments: stream -- A reference to an output
* stream.
* algorithm_x, algorithm_y -- Identifiers of the algorithms
* whose cross-comparison results
* should be displayed.
* data_type -- Determines the type of data to
* be displayed in the cell:
* 0 -- Model checking result
* cross-comparison
* statistics.
* 1 -- Model checking result
* cross-comparison
* statistics (initial
* state only).
* 2 -- Büchi automaton
* intersection check
* statistics.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
estream << ' ';
if (algorithm_x == algorithm_y && data_type != 2)
estream << string(21, ' ');
else
{
unsigned long int num_comparisons, num_mismatches;
const TestStatistics& stats = final_statistics[algorithm_y];
switch (data_type)
{
case 0 :
num_comparisons = stats.cross_comparisons_performed[algorithm_x];
num_mismatches = stats.cross_comparison_mismatches[algorithm_x];
break;
case 1 :
num_comparisons = stats.cross_comparisons_performed[algorithm_x];
num_mismatches
= stats.initial_cross_comparison_mismatches[algorithm_x];
break;
default :
if (configuration.global_options.statespace_generation_mode
& Configuration::PATH
&& (algorithm_x == round_info.number_of_translators
|| algorithm_y == round_info.number_of_translators))
{
estream << string(21, ' ');
return;
}
num_comparisons
= stats.buchi_intersection_checks_performed[algorithm_x];
num_mismatches = stats.buchi_intersection_check_failures[algorithm_x];
break;
}
if (num_comparisons > 0)
{
changeStreamFormatting(stream, 5, 0, ios::right);
estream << num_mismatches;
restoreStreamFormatting(stream);
estream << '/';
changeStreamFormatting(stream, 5, 0, ios::left);
estream << num_comparisons;
restoreStreamFormatting(stream);
estream << " (";
double percentage = static_cast<double>(num_mismatches)
/ static_cast<double>(num_comparisons)
* 100.0;
changeStreamFormatting(stream, 0, 2, ios::fixed);
estream << percentage;
restoreStreamFormatting(stream);
estream << "%)";
if (percentage < 100.0)
estream << ' ';
if (percentage < 10.0)
estream << ' ';
}
else
estream << " N/A" + string(14, ' ');
}
}
/* ========================================================================= */
void printCollectiveStats(ostream& stream, int indent)
/* ----------------------------------------------------------------------------
*
* Description: Displays average information about a series of tests for each
* tested algorithm:
* - average sizes of the Büchi and product automata
* - number of failed attempts to generate a Büchi automaton
* - number of failed consistency checks
* - number of failed path checks
* - cross-comparison mismatches
* - Büchi automata intersection emptiness check failures
*
* Arguments: stream -- A reference to an output stream.
* indent -- Number of spaces to leave on the left of the
* output.
*
* Returns: Nothing.
*
* ------------------------------------------------------------------------- */
{
Exceptional_ostream estream(&stream, ios::failbit | ios::badbit);
const string ind(indent, ' ');
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Display state space statistics.
*/
estream << '\n' + ind + "Statistics after round "
+ toString(round_info.current_round) + '\n'
+ ind + string(toString(round_info.current_round).length() + 23,
'*')
+ "\n\n\n";
if (configuration.global_options.do_comp_test
|| configuration.global_options.do_cons_test)
{
estream << ind + " State space statistics\n"
+ ind + " " + string(22, '=') + "\n\n"
+ ind + " " + toString(round_info.num_generated_statespaces)
+ " state spaces generated\n"
+ ind + " " + toString(round_info.total_statespace_states)
+ " states generated";
if (round_info.num_generated_statespaces > 0)
{
estream << " ("
+ toString(static_cast<double>
(round_info.total_statespace_states)
/ static_cast<double>
(round_info.num_generated_statespaces),
2)
+ " states per state space)";
}
estream << '\n' + ind + " "
+ toString(round_info.total_statespace_transitions)
+ " transitions generated";
if (round_info.num_generated_statespaces > 0)
{
estream << " ("
+ toString(static_cast<double>
(round_info.total_statespace_transitions)
/ static_cast<double>
(round_info.num_generated_statespaces),
2)
+ " transitions per state space)";
}
estream << "\n\n\n";
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Display LTL formula statistics.
*/
estream << ind + " LTL formula statistics\n"
+ ind + " " + string(22, '=') + "\n\n"
+ ind + " " + toString(round_info.num_processed_formulae)
+ " LTL formulas "
+ (!configuration.global_options.formula_input_filename.empty()
? "process"
: "generat")
+ "ed\n";
if (round_info.num_processed_formulae > 0
&& configuration.global_options.formula_input_filename.empty())
{
const map<unsigned long int, unsigned long int, less<unsigned long int>,
ALLOC(unsigned long int) >&
proposition_statistics
= configuration.formula_options.formula_generator.
propositionStatistics();
const map<int, unsigned long int, less<int>, ALLOC(unsigned long int) >
symbol_statistics
= configuration.formula_options.formula_generator.symbolStatistics();
estream << '\n' + ind + " Atomic symbol distribution:\n";
string symbol_name_string;
string symbol_number_string;
string symbol_distribution_string;
int number_of_symbols_printed = 0;
if (symbol_statistics.find(::Ltl::LTL_TRUE) != symbol_statistics.end())
{
const unsigned long int num
= symbol_statistics.find(::Ltl::LTL_TRUE)->second;
symbol_name_string += "true ";
const string number_string = toString(num);
symbol_number_string += number_string
+ string(12 - number_string.length(), ' ');
const string distribution_string
= toString(static_cast<double>(num)
/ static_cast<double>(round_info.num_processed_formulae),
3);
symbol_distribution_string += distribution_string
+ string(12 - distribution_string.length(),
' ');
number_of_symbols_printed++;
}
if (symbol_statistics.find(::Ltl::LTL_FALSE) != symbol_statistics.end())
{
const unsigned long int num
= symbol_statistics.find(::Ltl::LTL_FALSE)->second;
symbol_name_string += "false ";
const string number_string = toString(num);
symbol_number_string += number_string
+ string(12 - number_string.length(), ' ');
const string distribution_string
= toString(static_cast<double>(num)
/ static_cast<double>(round_info.num_processed_formulae),
3);
symbol_distribution_string += distribution_string
+ string(12 - distribution_string.length(),
' ');
number_of_symbols_printed++;
}
for (map<unsigned long int, unsigned long int,
less<unsigned long int>, ALLOC(unsigned long int) >
::const_iterator proposition = proposition_statistics.begin();
proposition != proposition_statistics.end();
++proposition)
{
const string name_string = "p" + toString(proposition->first);
symbol_name_string += name_string;
const string number_string = toString(proposition->second);
symbol_number_string += number_string;
const string distribution_string
= toString(static_cast<double>(proposition->second)
/ static_cast<double>(round_info.num_processed_formulae),
3);
symbol_distribution_string += distribution_string;
number_of_symbols_printed++;
if (number_of_symbols_printed % 5 == 0)
{
estream << ind + " symbol " + symbol_name_string + '\n'
+ ind + " # " + symbol_number_string + '\n'
+ ind + " #/formula " + symbol_distribution_string
+ "\n\n";
symbol_name_string = symbol_number_string = symbol_distribution_string
= "";
}
else
{
symbol_name_string += string(12 - name_string.length(), ' ');
symbol_number_string += string(12 - number_string.length(), ' ');
symbol_distribution_string += string(12 - distribution_string.length(),
' ');
}
}
if (number_of_symbols_printed % 5 != 0)
{
estream << ind + " symbol " + symbol_name_string + '\n'
+ ind + " # " + symbol_number_string + '\n'
+ ind + " #/formula " + symbol_distribution_string
+ "\n\n";
}
estream << ind + " Operator distribution:\n";
symbol_name_string = symbol_number_string = symbol_distribution_string
= "";
number_of_symbols_printed = 0;
for (map<int, unsigned long int, less<int>, ALLOC(unsigned long int) >
::const_iterator op = symbol_statistics.begin();
op != symbol_statistics.end();
++op)
{
if (op->first == ::Ltl::LTL_ATOM || op->first == ::Ltl::LTL_TRUE
|| op->first == ::Ltl::LTL_FALSE)
continue;
const string name_string = ::Ltl::infixSymbol(op->first);
symbol_name_string += name_string;
const string number_string = toString(op->second);
symbol_number_string += number_string;
const string distribution_string
= toString(static_cast<double>(op->second)
/ static_cast<double>(round_info.num_processed_formulae),
3);
symbol_distribution_string += distribution_string;
number_of_symbols_printed++;
if (number_of_symbols_printed % 5 == 0)
{
if (number_of_symbols_printed > 5)
estream << '\n';
estream << ind + " operator " + symbol_name_string + '\n'
+ ind + " # " + symbol_number_string + '\n'
+ ind + " #/formula " + symbol_distribution_string
+ '\n';
symbol_name_string = symbol_number_string = symbol_distribution_string
= "";
}
else
{
symbol_name_string += string(12 - name_string.length(), ' ');
symbol_number_string += string(12 - number_string.length(), ' ');
symbol_distribution_string += string(12 - distribution_string.length(),
' ');
}
}
if (number_of_symbols_printed % 5 != 0)
{
estream << ind + " operator " + symbol_name_string + '\n'
+ ind + " # " + symbol_number_string + '\n'
+ ind + " #/formula " + symbol_distribution_string
+ '\n';
}
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Display the following information for each algorithm:
* 0. Automata statistics.
* 1. Number of failures to compute Büchi automata.
* 2. Number of model checking result consistency check failures.
*/
string algorithm_name;
for (int i = 0; i <= 2; i++)
{
estream << '\n' + string(2 + indent, ' ');
switch (i)
{
case 1 :
estream << "Failures to compute Büchi automaton\n"
+ string(2 + indent, ' ') + string(35, '=') + '\n';
break;
case 2 :
if (!configuration.global_options.do_cons_test)
continue;
estream << "Model checking result consistency check failures\n"
+ string(2 + indent, ' ') + string(48, '=') + '\n';
break;
default :
break;
}
for (unsigned long int algorithm = 0;
algorithm < round_info.number_of_translators;
++algorithm)
{
estream << '\n' + string((i > 0 ? 4 : 2) + indent, ' ')
+ *(configuration.algorithms[algorithm].name) + '\n';
switch (i)
{
/*
* Display a table of automaton statistics.
*/
case 0 :
{
unsigned long int failures_to_compute_automaton;
unsigned long int automaton_count;
unsigned long int number_of_successful_instances;
unsigned long int total_number_of_states;
unsigned long int total_number_of_transitions;
const TestStatistics& stats = final_statistics[algorithm];
estream << string(2 + indent, ' ')
+ string(configuration.algorithms[algorithm].name
->length(), '=');
for (int k = 0; k < 2; k++)
{
if (k == 1 && !configuration.global_options.do_comp_test
&& !configuration.global_options.do_cons_test)
continue;
estream << "\n\n" + string(8 + indent, ' ')
+ (k == 0 ? "BÜCHI " : "PRODUCT") + string(7, ' ')
+ "| Number of | Number of |"
" Number of |\n"
+ string(8 + indent, ' ')
+ "AUTOMATA" + string(6, ' ')
+ "| automata | states |"
" transitions |\n"
+ string(7 + indent, ' ') + string(15, '-') + '+';
for (int j = 0; j < 3; j++)
estream << string(17, '-') + '+';
estream << '\n';
for (int j = 0; j < 3; j++)
{
estream << string(8 + indent, ' ');
switch (j)
{
case 0 : estream << "Pos. formulae"; break;
case 1 : estream << "Neg. formulae"; break;
default : estream << "All formulae "; break;
}
estream << " | ";
if (j < 2)
{
if (k == 0)
{
failures_to_compute_automaton
= stats.failures_to_compute_buchi_automaton[j];
automaton_count = stats.buchi_automaton_count[j];
total_number_of_states
= stats.total_number_of_buchi_states[j];
total_number_of_transitions
= stats.total_number_of_buchi_transitions[j];
}
else
{
failures_to_compute_automaton
= stats.failures_to_compute_product_automaton[j];
automaton_count = stats.product_automaton_count[j];
total_number_of_states
= stats.total_number_of_product_states[j];
total_number_of_transitions
= stats.total_number_of_product_transitions[j];
}
}
else
{
if (k == 0)
{
failures_to_compute_automaton =
stats.failures_to_compute_buchi_automaton[0]
+ stats.failures_to_compute_buchi_automaton[1];
automaton_count = stats.buchi_automaton_count[0]
+ stats.buchi_automaton_count[1];
total_number_of_states
= stats.total_number_of_buchi_states[0]
+ stats.total_number_of_buchi_states[1];
total_number_of_transitions
= stats.total_number_of_buchi_transitions[0]
+ stats.total_number_of_buchi_transitions[1];
}
else
{
failures_to_compute_automaton =
stats.failures_to_compute_product_automaton[0]
+ stats.failures_to_compute_product_automaton[1];
automaton_count = stats.product_automaton_count[0]
+ stats.product_automaton_count[1];
total_number_of_states
= stats.total_number_of_product_states[0]
+ stats.total_number_of_product_states[1];
total_number_of_transitions
= stats.total_number_of_product_transitions[0]
+ stats.total_number_of_product_transitions[1];
}
}
number_of_successful_instances =
automaton_count - failures_to_compute_automaton;
for (int z = 0; z < 2; z++)
{
if (z == 0)
{
changeStreamFormatting(stream, 15, 2, ios::right);
estream << number_of_successful_instances;
restoreStreamFormatting(stream);
}
else
estream << string(indent + 15, ' ') + "(avg.) |"
+ string(16, ' ');
estream << " | ";
if (number_of_successful_instances == 0)
estream << string(15, ' ');
else
{
changeStreamFormatting(stream, 15, 2,
ios::fixed | ios::right);
if (z == 0)
estream << total_number_of_states;
else
estream << total_number_of_states
/ static_cast<double>
(number_of_successful_instances);
restoreStreamFormatting(stream);
}
estream << " | ";
if (number_of_successful_instances == 0)
estream << string(15, ' ');
else
{
changeStreamFormatting(stream, 15, 2,
ios::fixed | ios::right);
if (z == 0)
estream << total_number_of_transitions;
else
estream << total_number_of_transitions
/ static_cast<double>
(number_of_successful_instances);
restoreStreamFormatting(stream);
}
estream << " |\n";
}
}
if (k == 0)
{
unsigned long int total_number_of_acceptance_sets;
double buchi_generation_time;
estream << '\n' + string(22 + indent, ' ')
+ "| Number of | Time consumed |\n"
+ string(22 + indent, ' ')
+ "| acceptance sets | (seconds) |\n"
+ string(7 + indent, ' ') + string(15, '-') + '+';
for (int j = 0; j < 2; j++)
estream << string(17, '-') + '+';
for (int j = 0; j < 3; j++)
{
estream << '\n' + string(8 + indent, ' ');
switch (j)
{
case 0 : estream << "Pos. formulae"; break;
case 1 : estream << "Neg. formulae"; break;
default : estream << "All formulae "; break;
}
estream << " | ";
if (j < 2)
{
failures_to_compute_automaton =
stats.failures_to_compute_buchi_automaton[j];
automaton_count = stats.buchi_automaton_count[j];
buchi_generation_time = stats.total_buchi_generation_time[j];
total_number_of_acceptance_sets
= stats.total_number_of_acceptance_sets[j];
}
else
{
failures_to_compute_automaton =
stats.failures_to_compute_buchi_automaton[0]
+ stats.failures_to_compute_buchi_automaton[1];
automaton_count = stats.buchi_automaton_count[0]
+ stats.buchi_automaton_count[1];
buchi_generation_time =
(stats.total_buchi_generation_time[0] >= 0.0
&& stats.total_buchi_generation_time[1] >= 0.0
? stats.total_buchi_generation_time[0]
+ stats.total_buchi_generation_time[1]
: -1.0);
total_number_of_acceptance_sets
= stats.total_number_of_acceptance_sets[0]
+ stats.total_number_of_acceptance_sets[1];
}
number_of_successful_instances =
automaton_count - failures_to_compute_automaton;
for (int z = 0; z < 2; z++)
{
if (number_of_successful_instances == 0)
estream << string(15, ' ');
else
{
changeStreamFormatting(stream, 15, 2,
ios::fixed | ios::right);
if (z == 0)
estream << total_number_of_acceptance_sets;
else
estream << total_number_of_acceptance_sets
/ static_cast<double>
(number_of_successful_instances);
restoreStreamFormatting(stream);
}
estream << " | ";
if (number_of_successful_instances == 0
|| buchi_generation_time < 0.0)
estream << string(15, ' ');
else
{
changeStreamFormatting(stream, 15, 2,
ios::fixed | ios::right);
if (z == 0)
estream << buchi_generation_time;
else
estream << buchi_generation_time
/ number_of_successful_instances;
restoreStreamFormatting(stream);
}
estream << " |";
if (z == 0)
estream << '\n' + string(indent + 15, ' ') + "(avg.) | ";
}
}
estream << '\n';
}
}
if (algorithm + 1 < round_info.number_of_translators)
estream << '\n';
break;
}
/*
* Display the number of automaton computation failures.
*/
case 1 :
{
unsigned long int number_of_failures;
unsigned long int total_count;
const TestStatistics& stats = final_statistics[algorithm];
for (int j = 0; j < 3; j++)
{
estream << string(8 + indent, ' ');
switch (j)
{
case 0 : estream << "Positive formulae: "; break;
case 1 : estream << "Negative formulae: "; break;
default : estream << "Total:" + string(13, ' '); break;
}
if (j < 2)
{
number_of_failures
= stats.failures_to_compute_buchi_automaton[j];
total_count = stats.buchi_automaton_count[j];
}
else
{
number_of_failures
= stats.failures_to_compute_buchi_automaton[0]
+ stats.failures_to_compute_buchi_automaton[1];
total_count = stats.buchi_automaton_count[0]
+ stats.buchi_automaton_count[1];
}
changeStreamFormatting(stream, 5, 0, ios::left);
estream << number_of_failures;
restoreStreamFormatting(stream);
estream << " [";
if (total_count > 0)
{
changeStreamFormatting(stream, 0, 2, ios::fixed);
estream << static_cast<double>(number_of_failures) / total_count
* 100.0;
restoreStreamFormatting(stream);
estream << "% of " << total_count;
}
else
estream << "no";
estream << " attempts]\n";
}
break;
}
/*
* Display the number of consistency check failures.
*/
case 2 :
{
const TestStatistics& stats = final_statistics[algorithm];
estream << string(8 + indent, ' ');
changeStreamFormatting(stream, 5, 0, ios::left);
estream << stats.consistency_check_failures;
restoreStreamFormatting(stream);
estream << " [";
if (stats.consistency_checks_performed > 0)
{
changeStreamFormatting(stream, 0, 2, ios::fixed);
estream << static_cast<double>(stats.consistency_check_failures)
/ stats.consistency_checks_performed
* 100.0;
restoreStreamFormatting(stream);
estream << "% of " << stats.consistency_checks_performed;
}
else
estream << "no";
estream << " checks performed]\n";
break;
}
}
}
estream << '\n';
}
estream << '\n';
if ((configuration.algorithms.size() > 1
&& configuration.global_options.do_comp_test)
|| configuration.global_options.do_intr_test)
{
vector<Configuration::AlgorithmInformation>::size_type
number_of_algorithms = configuration.algorithms.size();
int legend;
estream << ind + " Result inconsistency statistics\n"
+ ind + " " + string(31, '=') + '\n';
vector<TestStatistics, ALLOC(TestStatistics) >::size_type
algorithm_x, algorithm_y;
for (algorithm_x = 0; algorithm_x < number_of_algorithms;
algorithm_x += 2)
{
estream << '\n' + string(30 + indent, ' ');
for (int i = 0; i < 2; ++i)
{
if (algorithm_x + i < number_of_algorithms)
{
algorithm_name =
(*(configuration.algorithms[algorithm_x + i].name)).substr(0, 20);
estream << "| " + algorithm_name
+ string(21 - algorithm_name.length(), ' ');
}
}
estream << '|';
for (algorithm_y = 0; algorithm_y < number_of_algorithms;
algorithm_y++)
{
estream << "\n " + ind + string(26, '-');
for (int i = 0; i < 2; ++i)
{
if (algorithm_x + i < number_of_algorithms)
estream << '+' + string(22, '-');
}
estream << '+';
algorithm_name
= (*(configuration.algorithms[algorithm_y].name)).substr(0, 20);
bool algorithm_name_printed = false;
legend = 1;
for (int data_type = 0; data_type < 3; ++data_type)
{
if ((data_type < 2
&& configuration.global_options.do_comp_test
&& number_of_algorithms > 1
&& (data_type == 0
|| configuration.global_options.product_mode
== Configuration::GLOBAL))
|| (data_type == 2
&& configuration.global_options.do_intr_test))
{
estream << "\n " + ind
+ (!algorithm_name_printed
? algorithm_name
+ string(21 - algorithm_name.length(), ' ')
: string(21, ' '))
+ " ["
+ toString(legend)
+ "] ";
algorithm_name_printed = true;
legend++;
for (int i = 0; i < 2; ++i)
{
if (algorithm_x + i < number_of_algorithms)
{
estream << '|';
printCollectiveCrossComparisonStats(stream, algorithm_y,
algorithm_x + i,
data_type);
}
}
estream << '|';
}
}
}
estream << '\n';
}
legend = 1;
if (number_of_algorithms > 1 && configuration.global_options.do_comp_test)
{
if (configuration.global_options.product_mode == Configuration::GLOBAL)
{
estream << '\n' + string(indent + 4, ' ')
+ "[1] Model checking result cross-comparison failures\n"
+ string(indent + 9, ' ')
+ "(number of failures / number of global "
"cross-comparisons)\n";
legend++;
}
estream << '\n' + string(indent + 4, ' ') + '[' + toString(legend)
+ "] Model checking result cross-comparison failures "
"(initial state only)\n"
+ string(indent + 9, ' ')
+ "(number of failures / number of cross-comparisons)\n";
legend++;
}
if (configuration.global_options.do_intr_test)
estream << '\n' + string(indent + 4, ' ') + '[' + toString(legend)
+ "] Büchi automata intersection emptiness check "
"failures\n"
+ string(indent + 9, ' ')
+ "(number of failures / number of checks performed)";
estream << "\n\n";
}
estream.flush();
}
}