Exemplo n.º 1
0
        /// <inheritdoc/>
        public void Run(LoadedProblemGeneratorInput input)
        {
            #region Prepare readable writers

            // Prepare the name of readable output files
            var nameOfReadableFiles = $"{_settings.OutputFilePrefix}{input.Id}.{_settings.FileExtension}";

            // If we should write readable output without proofs
            using var readableOutputWithoutProofsWriter = _settings.WriteReadableOutputWithoutProofs
                                                          // Prepare the writer for it
                ? new StreamWriter(new FileStream(Path.Combine(_settings.ReadableOutputWithoutProofsFolder, nameOfReadableFiles), FileMode.Create, FileAccess.Write, FileShare.Read))
                                                          // Otherwise null
                : null;

            // If we should write readable output with proofs
            using var readableOutputWithProofsWriter = _settings.WriteReadableOutputWithProofs
                                                       // Prepare the writer for it
                ? new StreamWriter(new FileStream(Path.Combine(_settings.ReadableOutputWithProofsFolder, nameOfReadableFiles), FileMode.Create, FileAccess.Write, FileShare.Read))
                                                       // Otherwise null
                : null;

            // Local function that writes a line to both readable writers, if they are available
            void WriteLineToBothReadableWriters(string line = "")
            {
                // Write to the standard writer
                readableOutputWithoutProofsWriter?.WriteLine(line);

                // Write to the writer with proofs
                readableOutputWithProofsWriter?.WriteLine(line);
            }

            #endregion

            #region Prepare JSON writer

            // Prepare the name of the JSON output file
            var jsonOutputFileName = $"{_settings.OutputFilePrefix}{input.Id}.json";

            // If we should write the JSON output
            var jsonOutputWriter = _settings.WriteJsonOutput
                                   // Prepare the writer for it
                ? _factory.Create(Path.Combine(_settings.JsonOutputFolder, jsonOutputFileName))
                                   // Otherwise null
                : null;

            #endregion

            // Call the generation algorithm
            var(initialTheorems, outputs) = _generator.Generate(input);

            #region Write constructions

            // Write the constructions header
            WriteLineToBothReadableWriters($"Constructions:\n");

            // Write all of them
            input.Constructions.ForEach(construction => WriteLineToBothReadableWriters($" - {construction}"));

            // An empty line
            WriteLineToBothReadableWriters();

            #endregion

            #region Write the initial configuration

            // Prepare the formatter for the initial configuration
            var initialFormatter = new OutputFormatter(input.InitialConfiguration.AllObjects);

            // Write it
            WriteLineToBothReadableWriters("Initial configuration:\n");
            WriteLineToBothReadableWriters(initialFormatter.FormatConfiguration(input.InitialConfiguration));

            // Write its theorems, if there are any
            if (initialTheorems.Any())
            {
                WriteLineToBothReadableWriters("\nTheorems:\n");
                WriteLineToBothReadableWriters(InitialTheoremsToString(initialFormatter, initialTheorems));
            }

            #endregion

            #region Write other setup

            // Write iterations
            WriteLineToBothReadableWriters($"\nIterations: {input.NumberOfIterations}");

            // Write maximal numbers of objects of particular types
            WriteLineToBothReadableWriters($"{input.MaximalNumbersOfObjectsToAdd.Select(pair => $"MaximalNumberOf{pair.Key}s: {pair.Value}").ToJoinedString("\n")}\n");

            // Write whether we're excluding symmetry
            WriteLineToBothReadableWriters($"SymmetryGenerationMode: {input.SymmetryGenerationMode}");

            #endregion

            // Write results header
            WriteLineToBothReadableWriters($"Results:");

            // Log that we've started
            Log.Information("Generation has started.");

            #region Tracking variables

            // Prepare the number of generated configurations
            var numberOfGeneratedConfigurations = 0;

            // Prepare the total number of interesting theorems
            var numberOfInterestingTheorems = 0;

            // Prepare the total number of configurations with an interesting theorem
            var numberOfConfigurationsWithInterestingTheorem = 0;

            #endregion

            #region Start stopwatch

            // Prepare a stopwatch to measure the execution time
            var stopwatch = new Stopwatch();

            // Start it
            stopwatch.Start();

            #endregion

            // Begin writing of the JSON output file
            jsonOutputWriter?.BeginWriting();

            // Prepare the variable indicating whether we're writing best theorems,
            // which happens when we want to write them either readable or JSON form
            var writeBestTheorems = _settings.WriteReadableBestTheorems || _settings.WriteJsonBestTheorems;

            // Prepare the variable indicating the last time we rewrote the best theorems
            DateTimeOffset?lastTimeBestTheoremsWereRewritten = null;

            #region Generation loop

            // Run the generation
            foreach (var generatorOutput in outputs)
            {
                // Mark the configuration
                numberOfGeneratedConfigurations++;

                #region Logging progress

                // Find out if we should log progress and if yes, do it
                if (_settings.LogProgress && numberOfGeneratedConfigurations % _settings.ProgressLoggingFrequency == 0)
                {
                    // Calculate how long on average it takes to generate 'one batch' according to the progress frequency
                    var averageTime = (double)stopwatch.ElapsedMilliseconds / numberOfGeneratedConfigurations * _settings.ProgressLoggingFrequency;

                    // Based on whether we're creating best theorems, write how many of them we have
                    var bestTheoremString = $"{(writeBestTheorems ? $" ({_resolver.AllSorters.Select(pair => pair.sorter.BestTheorems.Count()).Sum()} after global merge)" : "")}";

                    // Log what we have
                    Log.Information("Generated configurations: {configurations}, after {time} ms, {frequency} in {averageTime:F2} ms on average, with {theorems} theorems{bestTheorems} " +
                                    "in {allConfigurations} configurations", numberOfGeneratedConfigurations, stopwatch.ElapsedMilliseconds, _settings.ProgressLoggingFrequency,
                                    averageTime, numberOfInterestingTheorems, bestTheoremString, numberOfConfigurationsWithInterestingTheorem);
                }

                #endregion

                // Skip configurations without theorems
                if (generatorOutput.NewTheorems.AllObjects.Count == 0)
                {
                    continue;
                }

                // Prepare the output of the analyzer
                GeneratedProblemAnalyzerOutputBase analyzerOutput;

                #region Analyzer call

                try
                {
                    // If we should look for proofs (because we should be writing them or analyze the inner inferences)
                    analyzerOutput = _settings.WriteInferenceRuleUsages || _settings.WriteReadableOutputWithProofs
                                     // Then call the analysis that construct them
                        ? (GeneratedProblemAnalyzerOutputBase)_analyzer.AnalyzeWithProofConstruction(generatorOutput, input.SymmetryGenerationMode)
                                     // Otherwise we don't need them
                        : _analyzer.AnalyzeWithoutProofConstruction(generatorOutput, input.SymmetryGenerationMode);
                }
                catch (Exception e)
                {
                    // If there is any sort of problem, we should make aware of it.
                    Log.Error(e, "There has been an exception while analyzing the configuration:\n\n{configuration}\n",
                              // Write the problematic configuration
                              new OutputFormatter(generatorOutput.Configuration.AllObjects).FormatConfiguration(generatorOutput.Configuration));

                    // And move on, we still might get something cool
                    continue;
                }

                #endregion

                // Count in interesting theorems
                numberOfInterestingTheorems += analyzerOutput.InterestingTheorems.Count;

                // If this is a configuration with an interesting theorem, count it in
                if (analyzerOutput.InterestingTheorems.Any())
                {
                    numberOfConfigurationsWithInterestingTheorem++;
                }

                // Write JSON output
                jsonOutputWriter?.Write(analyzerOutput.InterestingTheorems);

                #region Handling best theorems

                // If we are supposed to be handling best theorems, do so
                if (writeBestTheorems)
                {
                    // Take the interesting theorems
                    var theoremsToBeJudged = analyzerOutput.InterestingTheorems
                                             // Group by type
                                             .GroupBy(rankedTheorem => rankedTheorem.Theorem.Type);

                    try
                    {
                        // Prepare the set of sorters whose content changed
                        var updatedSorterTypes = new HashSet <TheoremType>();

                        // Mark all interesting theorems
                        analyzerOutput.InterestingTheorems
                        // Grouped by type
                        .GroupBy(rankedTheorem => rankedTheorem.Theorem.Type)
                        // Handle each group
                        .ForEach(group =>
                        {
                            // Let the sorter judge the theorems
                            _resolver.GetSorterForType(group.Key).AddTheorems(group, out var localBestTheoremChanged);

                            // If there is any local change, mark it
                            if (localBestTheoremChanged)
                            {
                                updatedSorterTypes.Add(group.Key);
                            }
                        });

                        // Find out if we should rewrite the best theorems, i.e. it must be allowed
                        var shouldWeRewriteBestTheorems = _settings.WriteBestTheoremsContinuously
                                                          // And either we haven't done it yet
                                                          && (lastTimeBestTheoremsWereRewritten == null ||
                                                          // Or the number of seconds that have passed since the last rewrote
                                                              DateTimeOffset.Now.ToUnixTimeSeconds() - lastTimeBestTheoremsWereRewritten.Value.ToUnixTimeSeconds()
                                                          // Is more than our specified interval
                                                              > _settings.BestTheoremsRewrittingIntervalInSeconds);

                        // If we should write best theorems continuously and it is time to it
                        if (shouldWeRewriteBestTheorems)
                        {
                            // Do it
                            RewriteBestTheorems(updatedSorterTypes);

                            // After the update where it was done last time
                            lastTimeBestTheoremsWereRewritten = DateTimeOffset.Now;
                        }
                    }
                    catch (Exception e)
                    {
                        // If there is any sort of problem, we should make aware of it.
                        Log.Error(e, "There has been an exception while sorting theorems of the configuration:\n\n{configuration}\n",
                                  // Write the problematic configuration
                                  new OutputFormatter(generatorOutput.Configuration.AllObjects).FormatConfiguration(generatorOutput.Configuration));
                    }
                }

                #endregion

                #region Human-readable output

                // Prepare a formatter for the generated configuration
                var formatter = new OutputFormatter(generatorOutput.Configuration.AllObjects);

                // Prepare the header so we can measure it
                var header = $"Configuration {numberOfGeneratedConfigurations}";

                // Construct the header with dashes
                var headerWithConfiguration = $"\n{new string('-', header.Length)}\n{header}\n{new string('-', header.Length)}\n\n" +
                                              // And the configuration
                                              $"{formatter.FormatConfiguration(generatorOutput.Configuration)}";

                #region Writing to the writer of readable output without proofs

                // If there is anything interesting to write
                if (analyzerOutput.InterestingTheorems.Any())
                {
                    // Write the header
                    readableOutputWithoutProofsWriter?.Write(headerWithConfiguration);

                    // Write the analysis results without proofs
                    readableOutputWithoutProofsWriter?.Write(AnalyzerOutputToString(formatter, analyzerOutput, writeProofs: false));

                    // Flush it
                    readableOutputWithProofsWriter?.Flush();
                }

                #endregion

                #region Writing to the writer of output with proofs

                // Write the header
                readableOutputWithProofsWriter?.Write(headerWithConfiguration);

                // Write the analysis results with proofs
                readableOutputWithProofsWriter?.Write(AnalyzerOutputToString(formatter, analyzerOutput, writeProofs: true));

                // Flush it
                readableOutputWithoutProofsWriter?.Flush();

                #endregion

                #endregion

                #region Inference rule usage statistics

                // If we should write inference rule usages
                if (_settings.WriteInferenceRuleUsages)
                {
                    // Mark the proofs
                    _tracker.MarkProofs(((GeneratedProblemAnalyzerOutputWithProofs)analyzerOutput).TheoremProofs.Values);

                    // Prepare the writer
                    using var inferenceRuleUsageWriter = new StreamWriter(new FileStream(_settings.InferenceRuleUsageFilePath, FileMode.Create, FileAccess.Write, FileShare.Read));

                    // Rewrite the stats file
                    inferenceRuleUsageWriter.Write(InferenceRuleUsagesToString());
                }

                #endregion
            }

            #endregion

            // Rewrite the best theorems after the generation is finished
            RewriteBestTheorems();

            // Prepare the string explaining the state after merge
            var afterMergeString = $"{(writeBestTheorems ? $"{_resolver.AllSorters.Select(pair => pair.sorter.BestTheorems.Count()).Sum()}" : "-")}";

            // Write end
            WriteLineToBothReadableWriters("\n------------------------------------------------");
            WriteLineToBothReadableWriters($"Generated configurations: {numberOfGeneratedConfigurations}");
            WriteLineToBothReadableWriters($"Configurations with an interesting theorem: {numberOfConfigurationsWithInterestingTheorem}");
            WriteLineToBothReadableWriters($"Interesting theorems: {numberOfInterestingTheorems}");
            WriteLineToBothReadableWriters($"Interesting theorems after global merge: {afterMergeString}");

            // Log these stats as well
            Log.Information("Generated configurations: {count}", numberOfGeneratedConfigurations);
            Log.Information("Configurations with an interesting theorem: {count}", numberOfConfigurationsWithInterestingTheorem);
            Log.Information("Interesting theorems: {count}", numberOfInterestingTheorems);
            Log.Information("Interesting theorems after global merge: {count}", afterMergeString);
            Log.Information("Run-time: {time} ms", stopwatch.ElapsedMilliseconds);

            // Close the JSON output writer
            jsonOutputWriter?.EndWriting();
        }
        /// <inheritdoc/>
        public void Run(LoadedProblemGeneratorInput input)
        {
            // Prepare the variable holding the number of generated configurations
            var generatedConfigurations = 0;

            // Prepare the stopwatch
            var stopwatch = new Stopwatch();

            // Start them
            stopwatch.Start();

            // Run the generation loop
            foreach (var output in _generator.Generate(input).generationOutputs)
            {
                // Switch based on how we calculate the count
                switch (_settings.CountingMode)
                {
                // If we're counting in only the last iteration
                case CountingMode.LastIteration:

                    // Check if this is the last iteration
                    if (output.Configuration.IterationIndex == input.NumberOfIterations)
                    {
                        // Count it in
                        generatedConfigurations++;
                    }

                    // Otherwise we may move on
                    else
                    {
                        continue;
                    }

                    break;

                // If we're counting in everything
                case CountingMode.All:

                    // Do it
                    generatedConfigurations++;

                    break;

                // Unhandled cases
                default:
                    throw new ConfigurationGenerationLauncherException($"Unhandled value of {nameof(CountingMode)}: {_settings.CountingMode}");
                }

                // If we're logging and if we should log
                if (_settings.LogProgress && generatedConfigurations % _settings.GenerationProgresLoggingFrequency == 0)
                {
                    // Prepare the used memory string
                    var usedMemory = ((double)GC.GetTotalMemory(forceFullCollection: true) / 1000000).ToStringWithDecimalDot();

                    // Log the number of generated configurations as well as the memory
                    Log.Information("Number of generated configurations: {count}, used memory: {memory} MB", generatedConfigurations, usedMemory);
                }
            }

            // Stop the timing
            stopwatch.Stop();

            // Log the final number and time
            Log.Information("The total number of generated configurations is {count} in {time} ms.", generatedConfigurations, stopwatch.ElapsedMilliseconds);
        }