Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ endif()
set(PROJECT_NAME libCellML)
set(PROJECT_URL https://libcellml.org)
set(_PROJECT_VERSION 0.7.0)
set(PROJECT_DEVELOPER_VERSION -rc.4)
set(PROJECT_DEVELOPER_VERSION )
project(${PROJECT_NAME} VERSION ${_PROJECT_VERSION} LANGUAGES CXX)

# Set policies that affect the build.
Expand Down
2 changes: 2 additions & 0 deletions docs/changelogs/changelog_v0.7.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
libCellML v0.7.0 Changelog
==========================
2 changes: 1 addition & 1 deletion docs/changelogs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Changelogs

.. toctree::

changelog_v0.7.0-rc.4
changelog_v0.7.0
changelog_v0.6.3
changelog_v0.6.2
changelog_v0.6.1
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Changelogs

.. toctree::

changelogs/changelog_v0.7.0-rc.4
changelogs/changelog_v0.7.0
changelogs/changelog_v0.6.3
changelogs/changelog_v0.6.2
changelogs/changelog_v0.6.1
Expand Down
12 changes: 12 additions & 0 deletions src/analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,17 @@ AnalyserInternalVariablePtr Analyser::AnalyserImpl::internalVariable(const Varia
// Find and return, if there is one, the internal variable associated with
// the given variable.

auto rawPtr = reinterpret_cast<uintptr_t>(variable.get());
auto rawPtrIt = mInternalVariableMap.find(rawPtr);

if (rawPtrIt != mInternalVariableMap.end()) {
return rawPtrIt->second;
}

for (const auto &internalVariable : mInternalVariables) {
if (mAnalyserModel->areEquivalentVariables(variable, internalVariable->mVariable)) {
mInternalVariableMap[rawPtr] = internalVariable;

return internalVariable;
}
}
Expand All @@ -416,6 +425,8 @@ AnalyserInternalVariablePtr Analyser::AnalyserImpl::internalVariable(const Varia

mInternalVariables.push_back(res);

mInternalVariableMap[rawPtr] = res;

return res;
}

Expand Down Expand Up @@ -2321,6 +2332,7 @@ void Analyser::AnalyserImpl::analyseModel(const ModelPtr &model)
mAnalyserModel = AnalyserModel::AnalyserModelImpl::create(model);

mInternalVariables.clear();
mInternalVariableMap.clear();
mInternalEquations.clear();

mCiCnUnits.clear();
Expand Down
1 change: 1 addition & 0 deletions src/analyser_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class Analyser::AnalyserImpl: public Logger::LoggerImpl
AnalyserExternalVariablePtrs mExternalVariables;

AnalyserInternalVariablePtrs mInternalVariables;
std::unordered_map<std::uintptr_t, AnalyserInternalVariablePtr> mInternalVariableMap;
AnalyserInternalEquationPtrs mInternalEquations;

GeneratorProfilePtr mGeneratorProfile = GeneratorProfile::create();
Expand Down
122 changes: 89 additions & 33 deletions src/analysermodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,50 @@ AnalyserModel::~AnalyserModel()
delete mPimpl;
}

void AnalyserModel::AnalyserModelImpl::buildEquivalentVariablesCache(const ComponentPtr &component)
void exploreEquivalentVariables(const VariablePtr &variable, std::unordered_set<uintptr_t> &equivalentGroup, std::unordered_set<uintptr_t> &visited)
{
for (size_t i = 0; i < component->variableCount(); ++i) {
auto variable = component->variable(i);

for (size_t j = 0; j < variable->equivalentVariableCount(); ++j) {
auto equivalentVariable = variable->equivalentVariable(j);
auto v1 = reinterpret_cast<uintptr_t>(variable.get());
auto v2 = reinterpret_cast<uintptr_t>(equivalentVariable.get());
auto rawPtr = reinterpret_cast<uintptr_t>(variable.get());

if (v2 < v1) {
std::swap(v1, v2);
}
if (visited.insert(rawPtr).second) {
equivalentGroup.insert(rawPtr);

uniteEquivalentVariableAddresses(v1, v2);
for (size_t i = 0; i < variable->equivalentVariableCount(); ++i) {
exploreEquivalentVariables(variable->equivalentVariable(i), equivalentGroup, visited);
}
}

for (size_t i = 0; i < component->componentCount(); ++i) {
buildEquivalentVariablesCache(component->component(i));
}
}

void AnalyserModel::AnalyserModelImpl::buildEquivalentVariablesCache()
{
std::unordered_set<uintptr_t> visited;
size_t groupCount = 0;
mEquivalentVariableCache.clear();

for (size_t i = 0; i < mModel->componentCount(); ++i) {
buildEquivalentVariablesCache(mModel->component(i));
buildEquivalentVariablesCache(mModel->component(i), visited, groupCount);
}
}

void AnalyserModel::AnalyserModelImpl::buildEquivalentVariablesCache(const ComponentPtr &component, std::unordered_set<uintptr_t> &visited, size_t &groupCount)
{
for (size_t i = 0; i < component->variableCount(); ++i) {
auto variable = component->variable(i);
auto rawPtr = reinterpret_cast<uintptr_t>(variable.get());

if (visited.count(rawPtr) == 0) {
std::unordered_set<uintptr_t> equivalentGroup;
exploreEquivalentVariables(variable, equivalentGroup, visited);

for (uintptr_t v : equivalentGroup) {
mEquivalentVariableCache[v] = groupCount;
}

++groupCount;
}
}

for (size_t i = 0; i < component->componentCount(); ++i) {
buildEquivalentVariablesCache(component->component(i), visited, groupCount);
}
}

Expand All @@ -98,20 +113,21 @@ AnalyserModel::Type AnalyserModel::type() const
return mPimpl->mType;
}

static const std::map<AnalyserModel::Type, std::string> typeToString = {
{AnalyserModel::Type::UNKNOWN, "unknown"},
{AnalyserModel::Type::ODE, "ode"},
{AnalyserModel::Type::DAE, "dae"},
{AnalyserModel::Type::NLA, "nla"},
{AnalyserModel::Type::ALGEBRAIC, "algebraic"},
{AnalyserModel::Type::INVALID, "invalid"},
{AnalyserModel::Type::UNDERCONSTRAINED, "underconstrained"},
{AnalyserModel::Type::OVERCONSTRAINED, "overconstrained"},
{AnalyserModel::Type::UNSUITABLY_CONSTRAINED, "unsuitably_constrained"}};

std::string AnalyserModel::typeAsString(Type type)
{
return typeToString.at(type);
static constexpr const char *names[] = {
"unknown",
"algebraic",
"dae",
"invalid",
"nla",
"ode",
"overconstrained",
"underconstrained",
"unsuitably_constrained",
};

return names[static_cast<size_t>(type)];
}

bool AnalyserModel::hasExternalVariables() const
Expand Down Expand Up @@ -274,9 +290,37 @@ AnalyserVariablePtr AnalyserModel::analyserVariable(const VariablePtr &variable)
return {};
}

for (const auto &analyserVariable : analyserVariables(shared_from_this())) {
if (areEquivalentVariables(variable, analyserVariable->variable())) {
return analyserVariable;
if (mPimpl->mVoi && areEquivalentVariables(variable, mPimpl->mVoi->variable())) {
return mPimpl->mVoi;
}

for (const auto &state : mPimpl->mStates) {
if (areEquivalentVariables(variable, state->variable())) {
return state;
}
}

for (const auto &constant : mPimpl->mConstants) {
if (areEquivalentVariables(variable, constant->variable())) {
return constant;
}
}

for (const auto &computedConstant : mPimpl->mComputedConstants) {
if (areEquivalentVariables(variable, computedConstant->variable())) {
return computedConstant;
}
}

for (const auto &algebraicVariable : mPimpl->mAlgebraicVariables) {
if (areEquivalentVariables(variable, algebraicVariable->variable())) {
return algebraicVariable;
}
}

for (const auto &externalVariable : mPimpl->mExternalVariables) {
if (areEquivalentVariables(variable, externalVariable->variable())) {
return externalVariable;
}
}

Expand Down Expand Up @@ -546,7 +590,19 @@ bool AnalyserModel::areEquivalentVariables(const VariablePtr &variable1,
const auto v1 = reinterpret_cast<uintptr_t>(variable1.get());
const auto v2 = reinterpret_cast<uintptr_t>(variable2.get());

return mPimpl->findVariableAddress(v1) == mPimpl->findVariableAddress(v2);
const auto it1 = mPimpl->mEquivalentVariableCache.find(v1);

if (it1 == mPimpl->mEquivalentVariableCache.end()) {
return false;
}

const auto it2 = mPimpl->mEquivalentVariableCache.find(v2);

if (it2 == mPimpl->mEquivalentVariableCache.end()) {
return false;
}

return it1->second == it2->second;
}

} // namespace libcellml
32 changes: 3 additions & 29 deletions src/analysermodel_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ limitations under the License.

#include <cstdint>
#include <unordered_map>
#include <unordered_set>

#include "libcellml/analysermodel.h"

Expand Down Expand Up @@ -46,34 +47,7 @@ struct AnalyserModel::AnalyserModelImpl

std::vector<AnalyserEquationPtr> mAnalyserEquations;

std::unordered_map<uintptr_t, uintptr_t> mEquivalentVariableCache;

uintptr_t findVariableAddress(uintptr_t x)
{
auto it = mEquivalentVariableCache.find(x);

if (it == mEquivalentVariableCache.end()) {
mEquivalentVariableCache[x] = x;

return x;
}

if (it->second != x) {
it->second = findVariableAddress(it->second);
}

return it->second;
}

void uniteEquivalentVariableAddresses(uintptr_t x, uintptr_t y)
{
const uintptr_t &rootX = findVariableAddress(x);
const uintptr_t &rootY = findVariableAddress(y);

if (rootX != rootY) {
mEquivalentVariableCache[rootY] = rootX;
}
}
std::unordered_map<uintptr_t, size_t> mEquivalentVariableCache;

bool mNeedEqFunction = false;
bool mNeedNeqFunction = false;
Expand Down Expand Up @@ -104,7 +78,7 @@ struct AnalyserModel::AnalyserModelImpl

static AnalyserModelPtr create(const ModelPtr &model = nullptr);

void buildEquivalentVariablesCache(const ComponentPtr &component);
void buildEquivalentVariablesCache(const ComponentPtr &component, std::unordered_set<uintptr_t> &visited, size_t &groupCount);
void buildEquivalentVariablesCache();

AnalyserModelImpl(const ModelPtr &model);
Expand Down
7 changes: 1 addition & 6 deletions src/api/libcellml/analysermodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,10 +604,6 @@ class LIBCELLML_EXPORT AnalyserModel
* analysis phase (@ref Analyser::analyseModel). The cache may become
* out of date if the model is changed after the model has been analysed.
*
* @note This function is primarily designed for use during model analysis
* by the @ref Analyser. While external usage is not programmatically
* restricted, it is not the primary intended use case.
*
* @param variable1 The @ref Variable to test if it is equivalent to
* @p variable2.
* @param variable2 The @ref Variable that is potentially equivalent to
Expand All @@ -616,8 +612,7 @@ class LIBCELLML_EXPORT AnalyserModel
* @return @c true if @p variable1 is equivalent to @p variable2 and
* @c false otherwise.
*/
bool areEquivalentVariables(const VariablePtr &variable1,
const VariablePtr &variable2);
bool areEquivalentVariables(const VariablePtr &variable1, const VariablePtr &variable2);

private:
AnalyserModel(const ModelPtr &model); /**< Constructor, @private. */
Expand Down
5 changes: 4 additions & 1 deletion src/api/libcellml/variable.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,17 @@ class LIBCELLML_EXPORT Variable: public NamedEntity
*
* Get the connection identifier set for the equivalence defined with the given variables.
* The variables are commutative. If no connection identifier is set the empty string is returned.
* The optional parameter @p deepSearch will traverse the equivalence network to find the connection identifier for the
* equivalence defined by the two variables. By default this is true.
*
* If the two variables are not equivalent the empty string is returned.
*
* @param variable1 Variable one of the equivalence.
* @param variable2 Variable two of the equivalence.
* @param deepSearch Optional parameter to deep search the equivalence network for the connection identifier, true by default.
* @return the @c std::string connection identifier.
*/
static std::string equivalenceConnectionId(const VariablePtr &variable1, const VariablePtr &variable2);
static std::string equivalenceConnectionId(const VariablePtr &variable1, const VariablePtr &variable2, bool deepSearch = true);

/**
* @brief Clear equivalent connection identifier for this equivalence.
Expand Down
5 changes: 4 additions & 1 deletion src/internaltypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ using VariableMap = std::vector<VariablePairPtr>; /**< Type definition for vecto
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 ComponentPair = std::pair<ComponentPtr, ComponentPtr>; /**< Type definition for Component pointer pair using standard library.*/
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.*/

Expand Down Expand Up @@ -79,6 +79,9 @@ using UnitsConstPtr = std::shared_ptr<const Units>; /**< Type definition for sha
using ConnectionMap = std::map<VariablePtr, VariablePtr>; /**< Type definition for a connection map.*/
using NamePairList = std::vector<NamePair>; /**< Type definition for a list of a pair of names. */

using ComponentRawPtrPair = std::pair<const Component *, const Component *>; /**< Type definition for pair of raw component pointers. */
using ConnectionIdMap = std::map<ComponentRawPtrPair, std::string>; /**< Type definition for map of pair of raw component pointers to connection ID. */

/**
* @brief Class for defining an epoch in the history of a @ref Component or @ref Units.
*
Expand Down
Loading
Loading