<commit_before>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "libcellml/printer.h"

#include <list>
#include <map>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

#include "libcellml/component.h"
#include "libcellml/enumerations.h"
#include "libcellml/importsource.h"
#include "libcellml/model.h"
#include "libcellml/reset.h"
#include "libcellml/units.h"
#include "libcellml/variable.h"

#include "utilities.h"

namespace libcellml {

// VariableMap
using VariablePair = std::pair<VariablePtr, VariablePtr>; /**< Type definition for VariablePtr pair.*/
using VariableMap = std::vector<VariablePair>; /**< Type definition for vector of VariablePair.*/
using VariableMapIterator = VariableMap::const_iterator; /**< Type definition of const iterator for vector of VariablePair.*/
// ComponentMap
using ComponentPair = std::pair<ComponentPtr, ComponentPtr>; /**< Type definition for Component pointer pair.*/
using ComponentMap = std::vector<ComponentPair>; /**< Type definition for vector of ComponentPair.*/
using ComponentMapIterator = ComponentMap::const_iterator; /**< Type definition of const iterator for vector of ComponentPair.*/

/**
 * @brief The Printer::PrinterImpl struct.
 *
 * The private implementation for the Printer class.
 */
struct Printer::PrinterImpl
{
    std::string printUnits(const UnitsPtr &units, const std::string &indent = "") const;
    std::string printComponent(const ComponentPtr &component, const std::string &indent = "") const;
    std::string printEncapsulation(const ComponentPtr &component, const std::string &indent = "") const;
    std::string printVariable(const VariablePtr &variable, const std::string &indent = "") const;
    std::string printReset(const ResetPtr &reset, const std::string &indent = "") const;
    std::string printResetChild(const std::string &childLabel, const std::string &childId, const std::string &math, const std::string &indent) const;
};

static const std::string tabIndent = "  ";
// Note: use the same number of spaces as libxml2 since we use it to format math
//       elements and this is done using a two-space indentation...

std::string printMapVariables(const VariablePair &variablePair, const std::string &indent)
{
    std::string mapVariables = indent + "<map_variables variable_1=\"" + variablePair.first->name() + "\""
                               + " variable_2=\"" + variablePair.second->name() + "\"";
    std::string mappingId = Variable::equivalenceMappingId(variablePair.first, variablePair.second);
    if (!mappingId.empty()) {
        mapVariables += " id=\"" + mappingId + "\"";
    }
    mapVariables += "/>\n";
    return mapVariables;
}

std::string printConnections(const ComponentMap &componentMap, const VariableMap &variableMap,
                             const std::string &indent)
{
    std::string connections;
    ComponentMap serialisedComponentMap;
    size_t componentMapIndex1 = 0;
    for (auto iterPair = componentMap.begin(); iterPair < componentMap.end(); ++iterPair) {
        ComponentPtr currentComponent1 = iterPair->first;
        ComponentPtr currentComponent2 = iterPair->second;
        ComponentPair currentComponentPair = std::make_pair(currentComponent1, currentComponent2);
        ComponentPair reciprocalCurrentComponentPair = std::make_pair(currentComponent2, currentComponent1);
        // Check whether this set of connections has already been serialised.
        bool pairFound = false;
        for (const auto &serialisedIterPair : serialisedComponentMap) {
            if ((serialisedIterPair == currentComponentPair) || (serialisedIterPair == reciprocalCurrentComponentPair)) {
                pairFound = true;
                break;
            }
        }
        // Continue to the next component pair if the current pair has already been serialised.
        if (pairFound) {
            ++componentMapIndex1;
            continue;
        }
        std::string mappingVariables;
        VariablePair variablePair = variableMap.at(componentMapIndex1);
        std::string connectionId = Variable::equivalenceConnectionId(variablePair.first, variablePair.second);
        mappingVariables += printMapVariables(variablePair, indent + tabIndent);
        // Check for subsequent variable equivalence pairs with the same parent components.
        size_t componentMapIndex2 = componentMapIndex1 + 1;
        for (auto iterPair2 = iterPair + 1; iterPair2 < componentMap.end(); ++iterPair2) {
            ComponentPtr nextComponent1 = iterPair2->first;
            ComponentPtr nextComponent2 = iterPair2->second;
            VariablePair variablePair2 = variableMap.at(componentMapIndex2);
            if ((currentComponent1 == nextComponent1) && (currentComponent2 == nextComponent2)) {
                mappingVariables += printMapVariables(variablePair2, indent + tabIndent);
                connectionId = Variable::equivalenceConnectionId(variablePair2.first, variablePair2.second);
            }
            ++componentMapIndex2;
        }
        // Serialise out the new connection.
        std::string connection = indent + "<connection";
        if (currentComponent1 != nullptr) {
            connection += " component_1=\"" + currentComponent1->name() + "\"";
        }
        if (currentComponent2 != nullptr) {
            connection += " component_2=\"" + currentComponent2->name() + "\"";
        }
        if (!connectionId.empty()) {
            connection += " id=\"" + connectionId + "\"";
        }
        connection += ">\n";
        connection += mappingVariables;
        connection += indent + "</connection>\n";
        connections += connection;
        serialisedComponentMap.push_back(currentComponentPair);
        ++componentMapIndex1;
    }

    return connections;
}

std::string printMath(const std::string &math, const std::string &indent)
{
    std::string repr;
    std::istringstream lines(math);
    std::string line;
    while (std::getline(lines, line, '\n')) {
        repr += indent + line + "\n";
    }
    return repr;
}

void buildMapsForComponentsVariables(const ComponentPtr &component, ComponentMap &componentMap, VariableMap &variableMap)
{
    for (size_t i = 0; i < component->variableCount(); ++i) {
        VariablePtr variable = component->variable(i);<commit_msg>Some minor cleaning up.<commit_after>/*
Copyright libCellML Contributors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "libcellml/printer.h"

#include <list>
#include <map>
#include <sstream>
#include <stack>
#include <utility>
#include <vector>

#include "libcellml/component.h"
#include "libcellml/enumerations.h"
#include "libcellml/importsource.h"
#include "libcellml/model.h"
#include "libcellml/reset.h"
#include "libcellml/units.h"
#include "libcellml/variable.h"

#include "utilities.h"

namespace libcellml {

// VariableMap
using VariablePair = std::pair<VariablePtr, VariablePtr>; /**< Type definition for VariablePtr pair.*/
using VariableMap = std::vector<VariablePair>; /**< Type definition for vector of VariablePair.*/
using VariableMapIterator = VariableMap::const_iterator; /**< Type definition of const iterator for vector of VariablePair.*/
// ComponentMap
using ComponentPair = std::pair<ComponentPtr, ComponentPtr>; /**< Type definition for Component pointer pair.*/
using ComponentMap = std::vector<ComponentPair>; /**< Type definition for vector of ComponentPair.*/
using ComponentMapIterator = ComponentMap::const_iterator; /**< Type definition of const iterator for vector of ComponentPair.*/

/**
 * @brief The Printer::PrinterImpl struct.
 *
 * The private implementation for the Printer class.
 */
struct Printer::PrinterImpl
{
    std::string printUnits(const UnitsPtr &units, const std::string &indent = "") const;
    std::string printComponent(const ComponentPtr &component, const std::string &indent = "") const;
    std::string printEncapsulation(const ComponentPtr &component, const std::string &indent = "") const;
    std::string printVariable(const VariablePtr &variable, const std::string &indent = "") const;
    std::string printReset(const ResetPtr &reset, const std::string &indent = "") const;
    std::string printResetChild(const std::string &childLabel, const std::string &childId, const std::string &math, const std::string &indent) const;
};

static const std::string tabIndent = "  ";
// Note: use the same number of spaces as libxml2 since we use it to format math
//       elements and this is done using a two-space indentation...

std::string printMapVariables(const VariablePair &variablePair, const std::string &indent)
{
    std::string mapVariables = indent + "<map_variables variable_1=\"" + variablePair.first->name() + "\""
                               + " variable_2=\"" + variablePair.second->name() + "\"";
    std::string mappingId = Variable::equivalenceMappingId(variablePair.first, variablePair.second);
    if (!mappingId.empty()) {
        mapVariables += " id=\"" + mappingId + "\"";
    }
    mapVariables += "/>\n";
    return mapVariables;
}

std::string printConnections(const ComponentMap &componentMap, const VariableMap &variableMap,
                             const std::string &indent)
{
    std::string connections;
    ComponentMap serialisedComponentMap;
    size_t componentMapIndex1 = 0;
    for (auto iterPair = componentMap.begin(); iterPair < componentMap.end(); ++iterPair) {
        ComponentPtr currentComponent1 = iterPair->first;
        ComponentPtr currentComponent2 = iterPair->second;
        ComponentPair currentComponentPair = std::make_pair(currentComponent1, currentComponent2);
        ComponentPair reciprocalCurrentComponentPair = std::make_pair(currentComponent2, currentComponent1);
        // Check whether this set of connections has already been serialised.
        bool pairFound = false;
        for (const auto &serialisedIterPair : serialisedComponentMap) {
            if ((serialisedIterPair == currentComponentPair) || (serialisedIterPair == reciprocalCurrentComponentPair)) {
                pairFound = true;
                break;
            }
        }
        // Continue to the next component pair if the current pair has already been serialised.
        if (pairFound) {
            ++componentMapIndex1;
            continue;
        }
        std::string mappingVariables;
        VariablePair variablePair = variableMap.at(componentMapIndex1);
        std::string connectionId = Variable::equivalenceConnectionId(variablePair.first, variablePair.second);
        mappingVariables += printMapVariables(variablePair, indent + tabIndent);
        // Check for subsequent variable equivalence pairs with the same parent components.
        size_t componentMapIndex2 = componentMapIndex1 + 1;
        for (auto iterPair2 = iterPair + 1; iterPair2 < componentMap.end(); ++iterPair2) {
            ComponentPtr nextComponent1 = iterPair2->first;
            ComponentPtr nextComponent2 = iterPair2->second;
            VariablePair variablePair2 = variableMap.at(componentMapIndex2);
            if ((currentComponent1 == nextComponent1) && (currentComponent2 == nextComponent2)) {
                mappingVariables += printMapVariables(variablePair2, indent + tabIndent);
                connectionId = Variable::equivalenceConnectionId(variablePair2.first, variablePair2.second);
            }
            ++componentMapIndex2;
        }
        // Serialise out the new connection.
        std::string connection = indent + "<connection";
        if (currentComponent1 != nullptr) {
            connection += " component_1=\"" + currentComponent1->name() + "\"";
        }
        if (currentComponent2 != nullptr) {
            connection += " component_2=\"" + currentComponent2->name() + "\"";
        }
        if (!connectionId.empty()) {
            connection += " id=\"" + connectionId + "\"";
        }
        connection += ">\n";
        connection += mappingVariables;
        connection += indent + "</connection>\n";
        connections += connection;
        serialisedComponentMap.push_back(currentComponentPair);
        ++componentMapIndex1;
    }

    return connections;
}

std::string printMath(const std::string &math, const std::string &indent)
{
    std::string repr;
    std::istringstream lines(math);
    std::string line;
    while (std::getline(lines, line)) {
        repr += indent + line + "\n";
    }
    return repr;
}

void buildMapsForComponentsVariables(const ComponentPtr &component, ComponentMap &componentMap, VariableMap &variableMap)
{
    for (size_t i = 0; i < component->variableCount(); ++i) {
        VariablePtr variable = component->variable(i);
{'fraction_non_alphanumeric': 0.11090722254844393, 'fraction_numerical': 0.006752789195537287, 'mean_word_length': 3.5644891122278057, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3167616', 'n_tokens_mistral': 3573, 'n_tokens_neox': 3470, 'n_words': 1043}