mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
238 lines
5.5 KiB
C++
238 lines
5.5 KiB
C++
/*
|
|
This file is part of solidity.
|
|
|
|
solidity 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
// SPDX-License-Identifier: GPL-3.0
|
|
|
|
#include <libsolutil/LinearExpression.h>
|
|
|
|
using namespace solidity::util;
|
|
using namespace std;
|
|
|
|
SparseMatrix::SparseMatrixIterator SparseMatrix::IteratorCombiner::begin()
|
|
{
|
|
if (
|
|
(m_isRow && m_rowOrColumn >= m_matrix.m_row_start.size()) ||
|
|
(!m_isRow && m_rowOrColumn >= m_matrix.m_col_start.size())
|
|
)
|
|
return SparseMatrixIterator(nullptr, m_isRow);
|
|
else
|
|
return SparseMatrixIterator(
|
|
m_isRow ? m_matrix.m_row_start[m_rowOrColumn] : m_matrix.m_col_start[m_rowOrColumn],
|
|
m_isRow
|
|
);
|
|
}
|
|
|
|
SparseMatrix::SparseMatrixIterator SparseMatrix::IteratorCombiner::end()
|
|
{
|
|
return SparseMatrixIterator(nullptr, m_isRow);
|
|
}
|
|
|
|
SparseMatrix::IteratorCombiner SparseMatrix::iterateColumn(size_t _column)
|
|
{
|
|
return IteratorCombiner{
|
|
_column,
|
|
false,
|
|
*this
|
|
};
|
|
}
|
|
|
|
SparseMatrix::IteratorCombiner SparseMatrix::iterateRow(size_t _row)
|
|
{
|
|
return IteratorCombiner{
|
|
_row,
|
|
true,
|
|
*this
|
|
};
|
|
}
|
|
|
|
void SparseMatrix::multiplyRowByFactor(size_t _row, rational const& _factor)
|
|
{
|
|
Entry* e = m_row_start[_row];
|
|
while (e)
|
|
{
|
|
e->value *= _factor;
|
|
Entry* next = e->next_in_row;
|
|
if (!e->value)
|
|
remove(*e);
|
|
e = next;
|
|
}
|
|
}
|
|
|
|
void SparseMatrix::addMultipleOfRow(size_t _sourceRow, size_t _targetRow, rational const& _factor)
|
|
{
|
|
if (_targetRow >= m_row_start.size())
|
|
{
|
|
m_row_start.resize(_targetRow + 1);
|
|
m_row_end.resize(_targetRow + 1);
|
|
}
|
|
Entry* source = m_row_start[_sourceRow];
|
|
Entry* target = m_row_start[_targetRow];
|
|
|
|
while (source)
|
|
{
|
|
while (target && target->col < source->col)
|
|
target = target->next_in_row;
|
|
if (target && target->col == source->col)
|
|
{
|
|
target->value += _factor * source->value;
|
|
if (!target->value)
|
|
{
|
|
Entry* next = target->next_in_row;
|
|
remove(*target);
|
|
target = next;
|
|
}
|
|
}
|
|
target = prependInRow(target, _targetRow, source->col, _factor * source->value)->next_in_row;
|
|
|
|
source = source->next_in_row;
|
|
}
|
|
}
|
|
|
|
SparseMatrix::Entry& SparseMatrix::entry(size_t _row, size_t _column)
|
|
{
|
|
Entry* successor = entryOrSuccessorInRow(_row, _column);
|
|
if (successor && successor->col == _column)
|
|
return *successor;
|
|
else
|
|
return *prependInRow(successor, _row, _column, {});
|
|
}
|
|
|
|
void SparseMatrix::insert(size_t _row, size_t _column, rational _value)
|
|
{
|
|
if (_column >= m_col_start.size())
|
|
{
|
|
m_col_start.resize(_column + 1);
|
|
m_col_end.resize(_column + 1);
|
|
}
|
|
if (_row >= m_row_start.size())
|
|
{
|
|
m_row_start.resize(_row + 1);
|
|
m_row_end.resize(_row + 1);
|
|
}
|
|
|
|
prependInRow(entryOrSuccessorInRow(_row, _column), _row, _column, move(_value));
|
|
}
|
|
|
|
void SparseMatrix::appendRow(LinearExpression const& _entries)
|
|
{
|
|
m_row_start.push_back(nullptr);
|
|
m_row_end.push_back(nullptr);
|
|
size_t row_nr = m_row_start.size() - 1;
|
|
for (auto&& [i, v]: _entries.enumerate()) {
|
|
if (!v)
|
|
continue;
|
|
prependInRow(nullptr, row_nr, i, move(v));
|
|
}
|
|
}
|
|
|
|
SparseMatrix::Entry* SparseMatrix::entryOrSuccessorInRow(size_t _row, size_t _column)
|
|
{
|
|
Entry* successor = nullptr;
|
|
if (m_row_end[_row] && m_row_end[_row]->col >= _column)
|
|
{
|
|
successor = m_row_start[_row];
|
|
// TODO could choose to search from end
|
|
while (successor && successor->col < _column)
|
|
successor = successor->next_in_row;
|
|
}
|
|
return successor;
|
|
}
|
|
|
|
void SparseMatrix::remove(SparseMatrix::Entry& _e)
|
|
{
|
|
if (_e.prev_in_row)
|
|
_e.prev_in_row->next_in_row = _e.next_in_row;
|
|
else
|
|
m_row_start[_e.row] = _e.next_in_row;
|
|
if (_e.next_in_row)
|
|
_e.next_in_row->prev_in_row = _e.prev_in_row;
|
|
else
|
|
m_row_end[_e.row] = _e.prev_in_row;
|
|
if (_e.prev_in_col)
|
|
_e.prev_in_col->next_in_col = _e.next_in_col;
|
|
else
|
|
m_col_start[_e.col] = _e.next_in_col;
|
|
if (_e.next_in_col)
|
|
_e.next_in_col->prev_in_col = _e.prev_in_col;
|
|
else
|
|
m_col_end[_e.col] = _e.prev_in_col;
|
|
}
|
|
|
|
SparseMatrix::Entry* SparseMatrix::prependInRow(Entry* _successor, size_t _row, size_t _column, rational _value)
|
|
{
|
|
m_elements.emplace_back(make_unique<Entry>(Entry{
|
|
move(_value),
|
|
_row,
|
|
_column,
|
|
nullptr,
|
|
_successor,
|
|
nullptr,
|
|
nullptr
|
|
}));
|
|
Entry* e = m_elements.back().get();
|
|
if (_successor)
|
|
{
|
|
e->prev_in_row = _successor->prev_in_row;
|
|
_successor->prev_in_row = e;
|
|
}
|
|
else
|
|
{
|
|
e->prev_in_row = m_row_end[_row];
|
|
m_row_end[_row] = e;
|
|
}
|
|
if (e->prev_in_row)
|
|
e->prev_in_row->next_in_row = e;
|
|
else
|
|
m_row_start[_row] = e;
|
|
|
|
adjustColumnProperties(*e);
|
|
return e;
|
|
}
|
|
|
|
void SparseMatrix::adjustColumnProperties(Entry& _entry)
|
|
{
|
|
size_t column = _entry.col;
|
|
|
|
if (column >= m_col_start.size())
|
|
{
|
|
m_col_start.resize(column + 1);
|
|
m_col_end.resize(column + 1);
|
|
}
|
|
Entry* c = nullptr;
|
|
if (m_col_end[column] && m_col_end[column]->row > _entry.row)
|
|
{
|
|
c = m_col_start[column];
|
|
// TODO could choose to search from end
|
|
while (c && c->row < _entry.row)
|
|
c = c->next_in_col;
|
|
}
|
|
_entry.next_in_col = c;
|
|
if (c)
|
|
{
|
|
_entry.prev_in_col = c->prev_in_col;
|
|
c->prev_in_col = &_entry;
|
|
}
|
|
else
|
|
{
|
|
_entry.prev_in_col = m_col_end[column];
|
|
m_col_end[column] = &_entry;
|
|
}
|
|
if (_entry.prev_in_col)
|
|
_entry.prev_in_col->next_in_col = &_entry;
|
|
else
|
|
m_col_start[column] = &_entry;
|
|
}
|