Лучший способ сохранить разреженную матрицу в.NET

Вы можете установить высоту (количество видимых линий) JTextArea, используя setRows(). Попробуйте приведенный ниже пример. Я начал с вашего кода и сделал несколько изменений.

import javax.swing.*;
import java.awt.*;

public class ThreeLinesTextArea
{
  public static void main(String[] args)
  {
    JPanel pane = new JPanel();
    // Change to GridBagLayout
    pane.setLayout(new GridBagLayout());
    JTextField url = new JTextField("https:testin.com");
    JTextField username = new JTextField("theDude");

    JTextArea statement = new JTextArea("This statement can becomme very very very long :)");
    statement.setLineWrap(true);
    statement.setWrapStyleWord(true);
    // Use setRows() to make text area have multiple lines
    statement.setRows(3);
    JScrollPane scrollPane = new JScrollPane(statement);

    //This line is removed. scrollPane is added at the end.
    //pane.add(scrollPane);

    pane.add(new JLabel("Enter url: "),
        new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(url,
        new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(new JLabel("Enter username: "),
        new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(username,
        new GridBagConstraints(1, 1, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(new JLabel("Enter password: "),
        new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(new JPasswordField(15),
        new GridBagConstraints(1, 2, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(new JLabel("Enter statement: "),
        new GridBagConstraints(0, 3, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
    pane.add(scrollPane,
        new GridBagConstraints(1, 3, 1, 1, 1.0, 1.0, GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL, new Insets(2, 2, 2, 2), 0, 0));

    int option = JOptionPane.showConfirmDialog(null, pane, "Fill all the fields",
        JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE);
  }
}

Вывод:

enter image description here

10
задан Jeffrey Cameron 16 April 2009 в 15:49
поделиться

6 ответов

You could use an index based on the [row,col] of the cell. Since the data is on a diagonal, the typical approach of storing the row index and the associated column indeces with data is not optimal. Here is some code you could use to do it:

    public class SparseMatrix<T>
    {
        public int Width { get; private set; }
        public int Height { get; private set; }
        public long Size { get; private set; }

        private Dictionary<long, T> _cells = new Dictionary<long, T>();

        public SparseMatrix(int w, int h)
        {
            this.Width = w;
            this.Height = h;
            this.Size = w * h;
        }

        public bool IsCellEmpty(int row, int col)
        {
            long index = row * Width + col;
            return _cells.ContainsKey(index);
        }

        public T this[int row, int col]
        {
            get
            {
                long index = row * Width + col;
                T result;
                _cells.TryGetValue(index, out result);
                return result;
            }
            set
            {
                long index = row * Width + col;
                _cells[index] = value;
            }
        }
    }

    static void Main()
    {
        var sm = new SparseMatrix<int>(512, 512);
        sm[42, 42] = 42;
        int val1 = sm[13, 13];
        int val2 = sm[42, 42];

        Console.WriteLine("VAL1 = " + val1); // prints out 0
        Console.WriteLine("VAL2 = " + val2); // prints out 42

        Console.ReadLine();
    }

Note that when T is a struct, you might have to call the IsCellEmpty since getting the contents of a cell will not be null and will have the default value for that type. You can also expand the code to give you a quick "SparseRatio" based on the Size property and _cells.Count.

EDIT:

Well, if you are interesting is speed, you can do the trade-off of space vs speed. Instead of having only one dictionary, have three! It triples your space, but it makes enumerating in any way you want real easy. Here is some new code that shows that:

    public class SparseMatrix<T>
    {
        public int Width { get; private set; }
        public int Height { get; private set; }
        public long MaxSize { get; private set; }
        public long Count { get { return _cells.Count; } }

        private Dictionary<long, T> _cells = new Dictionary<long, T>();

        private Dictionary<int, Dictionary<int, T>> _rows = 
            new Dictionary<int, Dictionary<int, T>>();

        private Dictionary<int, Dictionary<int, T>> _columns = 
            new Dictionary<int, Dictionary<int, T>>();

        public SparseMatrix(int w, int h)
        {
            this.Width = w;
            this.Height = h;
            this.MaxSize = w * h;
        }

        public bool IsCellEmpty(int row, int col)
        {
            long index = row * Width + col;
            return _cells.ContainsKey(index);
        }

        public T this[int row, int col]
        {
            get
            {
                long index = row * Width + col;
                T result;
                _cells.TryGetValue(index, out result);
                return result;
            }
            set
            {
                long index = row * Width + col;
                _cells[index] = value;

                UpdateValue(col, row, _columns, value);
                UpdateValue(row, col, _rows, value);
            }
        }

        private void UpdateValue(int index1, int index2, 
            Dictionary<int, Dictionary<int, T>> parent, T value)
        {
            Dictionary<int, T> dict;
            if (!parent.TryGetValue(index1, out dict))
            {
                parent[index2] = dict = new Dictionary<int, T>();
            }
            dict[index2] = value;
        }
    }

If you want to iterate over all the entries, use _cells. If you want all the rows for a given column use _columns. If you want all the columns in a given row use _rows.

If you want to iterate in sorted order, you can start to add LINQ into the mix and/or use a sorted list with an inner class that encapsulates an entry (which would have to store the row or column and implement IComparable for sorting to work).

8
ответ дан 3 December 2019 в 19:35
поделиться

Полагаю, словаря > было бы достаточно.

4
ответ дан 3 December 2019 в 19:35
поделиться

Здесь есть два вопроса:

  • «В основном по главной диагонали» слишком расплывчато. Если элементы лежат в полосах, то используйте полосовое хранение самих полос, поскольку векторы смещены от главной диагонали. Если элементы разбросаны случайным образом в окрестности главной диагонали, то либо используйте полосчатую форму, которая может включать в себя несколько нулей в полосах, либо используйте чисто разреженную форму, которая хранит только элементы и их позиции в массиве.

  • Что вы будете делать с матрицей? Если ваша цель - просто эффективное хранилище, то эффективная полосчатая форма с быстрым доступом к любому элементу. Если вы будете выполнять линейную алгебру с матрицей, но не больше, чем умножение вектора матрицы , то полосовая форма все равно будет работать великолепно. Если вы работаете с матричным умножением или матричными факторизациями, где заполнение становится проблемой, тогда более разреженная форма может быть более подходящей. Например, произведение двух полосчатых матриц будет иметь дополнительные полосы, поэтому произведение двух трехдиагональных матриц будет пятиугольным. Для факторизации переупорядочения иногда будут полезны для минимизации заполнения. (AMD - один из вариантов, перестановка Приблизительная минимальная степень, но существуют и другие схемы.)

3
ответ дан 3 December 2019 в 19:35
поделиться

Я не использовал его, но Nmath Matrix обрабатывает их (не бесплатно).

Кроме того, Числовые библиотеки экстремальной оптимизации для .NET (не бесплатно).

Вот бесплатная версия: Проект Math.NET (в частности, MathNet.Numerics.LinearAlgebra .Sparse namespace )

2
ответ дан 3 December 2019 в 19:35
поделиться

I think this could be done by using a class holding plain array, saving the horizontal offset applied between matrix rows and defining stripe of a row, e.g. the number of valid entries. So for a large matrix where only the diagonal and two neighbor elements are defined you'd create an array of 3 * number of rows and store 3 as the stripe width. The offset depends on the size of the matrix.

I'm not aware of anything free which already does this.

1
ответ дан 3 December 2019 в 19:35
поделиться

Вот список общих схем структур данных . У каждого есть свои преимущества и недостатки, и они подходят для слегка различного рода задач, где возникают разреженные матрицы. Возможно, вы захотите реализовать их поверх существующих структур данных, таких как List <> и Dictionary <>.

2
ответ дан 3 December 2019 в 19:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: