МСС ресурс Freeware Open source Кафедра МСС Факультет  

Пакет
"Моделювання
Динамічних Систем"
v5.2

ПРО ПАКЕТ ПОПЕРЕДНІЙ КЛАС НАСТУПНИЙ КЛАС      

result.h
Клас result_manager

multimap
  |
  +--result_manager

Рекомендовані зовнішні модулі :
JEDIgviewer
 

Даний клас призначено для накопичення поточних результатів обчислень вигляду t, x1(t),...,xn(t), (n>=0), їх обробки та зберігання. Клас зручно використовувати як вхідний параметр для функцій моделювання, інтегрування тощо. В якості контейнера даних використано multimap<T_index,valarray<T_data> >. Файл зберігається у текстовому форматі. Передбачено можливість редагування формату файлу для забезпечення сумісності з табличними та графічними візуалізаторами. Зокрема, для перегляду n-вимірних графіків, які записані за допомогою даного класу, рекомендується використовувати JEDIgviewer.

У режимі відладки (DEBUG) здійснюється автоматичний контроль допустимості операцій.

У файлі mds.h визначено наступні типи.
typedef double MDS_DEFAULT_TYPE;
typedef mds_exception_message MDS_DEFAULT_EXCEPTION;
typedef result_manager <MDS_DEFAULT_TYPE, MDS_DEFAULT_TYPE, MDS_DEFAULT_EXCEPTION> ResultManager;


 

Члени класу
private string autosave_comment
           Коментар, що буде записаний у файл при автозаписі.
private string autosave_file_name
           Ім'я файлу, куди будуть записуватися результати при автозаписі (порожнє ім'я блокує запис).
private size_t cntDensity
           Внутрішня змінна (лічильник).
size_t density
           Щільність поповнення контейнеру даних: (density-1) елемент ігнорується, а наступний запам'ятовується; якщо density = 1 (по замовчуванню), то записуються всі дані, що поступають, якщо density = 0, то дані ігноруються.
bool autosave
           Режим автозапису у файл: true - включено (по замовчуванню), false - відключено. Автозапис - це запуск функції зберігання даних у файл автоматично з деструктора.
char separator
           Додатковий символ-роздільник між значеннями при записі у файл (по замовчуванню: ' ' - пробіл). Даний символ (якщо він не є пробілом) буде вставлений перед пробілом, який розділяє дані при записі у файл.
char remark_mark
           Символ-роздільник, з якого починається коментар при записі у файл (по замовчуванню: ';' - крапка з комою).

 

Конструктори
result_manager <class Tind = MDS_DEFAULT_TYPE, class Tdata = MDS_DEFAULT_TYPE, class EXCEPTION = MDS_DEFAULT_EXCEPTION, class Cmp = less<Tind>, class A = allocator<pair<const Tind, valarray<Tdata> > > > (const char* name = "", const char* comm = "")
             Параметри: name - ім'я файлу, куди будуть записуватися результати при автозаписі (порожнє ім'я блокує запис), comm - коментар, що буде записаний у файлі, створеному при автозаписі. Типи: Tind - тип аргументу (індекс або ключ), Tdata - тип значень (які будуть записані у вигляді valarray<Tdata>), EXCEPTION - тип винятків, Cmp - порівняння, A - виділення пам'яті.

 

Функції-члени класу
int Add(const T_index& arg, const valarray<T_data>& src, bool isReplace = false)
           Поповнення контейнеру даних із src з індексом arg. Реальне поповнення відбувається з урахуванням щільності density. Параметр isReplace визначає чи дані будуть заміщені (true) у випадку співпадання ключів, чи добавлені (false). Повертає 0, якщо реально відбулося поповнення контейнеру.
 int

Add(const T_index& arg, const T_data& src, bool isReplace = false)
           Поповнення контейнеру даних із src з індексом arg. Реальне поповнення відбувається з урахуванням щільності density. Параметр isReplace визначає чи дані будуть заміщені (true) у випадку співпадання ключів, чи добавлені (false). Повертає 0, якщо реально відбулося поповнення контейнеру.

int

Add(const T_index& arg, bool isReplace = false)
           Поповнення контейнеру даних із arg (створення множини аргументів). Реальне поповнення відбувається з урахуванням щільності density. Параметр isReplace визначає чи дані будуть заміщені (true) у випадку співпадання ключів, чи добавлені (false). Повертає 0, якщо реально відбулося поповнення контейнеру.

int

Add(const result_manager& src, bool isReplace = false)
           Поповнення контейнеру даних з іншого контейнеру src. Реальне поповнення відбувається з урахуванням щільності density. Параметр isReplace визначає чи дані будуть заміщені (true) у випадку співпадання ключів, чи добавлені (false). Повертає 0, якщо реально відбулося поповнення контейнеру.

result_manager&

operator += (const Tdata& src)
           Просте перетворення контейнеру даних (зсув): до всіх значень, які містяться у valarray<T_data> буде додано src.

result_manager&

operator -= (const Tdata& src)
           Просте перетворення контейнеру даних (зсув): від всіх значень, які містяться у valarray<T_data> буде віднято src.

result_manager&

operator *= (const Tdata& src)
           Просте перетворення контейнеру даних (розтяг): всі значення, які містяться у valarray<T_data> будуть помножені на src.

result_manager&

operator /= (const Tdata& src)
           Просте перетворення контейнеру даних (розтяг): всі значення, які містяться у valarray<T_data> будуть поділені на src.

void
Modify(iterator first, iterator last, Tdata fn(Tdata), const valarray<bool>& mask = valarray<bool>(size_t(0)))
           Застосування функції fn до всіх елементів контейнеру, які розташовані у інтервалі [first,last), але з урахуванням маски: функція буде застосована тільки до тих елементів масиву, індекси яких відповідають індексам з елементами true маски mask (за замовчуванням - всі елементи). Зауваження: розмірність маски не повинна перевищувати розмірність даних, до яких вона застосовується; маска нульової розмірності означає застосування функції fn до всіх елементів.
void
Modify(Tdata fn(Tdata), const valarray<bool>& mask = valarray<bool>(size_t(0)))
           Застосування функції fn до всіх елементів контейнеру, але з урахуванням маски: функція буде застосована тільки до тих компонентів масиву, індекси яких відповідають індексам з елементами true маски mask (за замовчуванням - всі компоненти). Зауваження: розмірність маски не повинна перевищувати розмірність даних, до яких вона застосовується; маска нульової розмірності означає застосування функції fn до всіх елементів.
void
Modify(iterator first, iterator last, Tdata fn(const Tdata&), const valarray<bool>& mask = valarray<bool>(size_t(0)))
           Застосування функції fn до всіх елементів контейнеру, які розташовані у інтервалі [first,last), але з урахуванням маски: функція буде застосована тільки до тих елементів масиву, індекси яких відповідають індексам з елементами true маски mask (за замовчуванням - всі елементи). Зауваження: розмірність маски не повинна перевищувати розмірність даних, до яких вона застосовується; маска нульової розмірності означає застосування функції fn до всіх елементів.
void
Modify(Tdata fn(const Tdata&), const valarray<bool>& mask = valarray<bool>(size_t(0)))
           Застосування функції fn до всіх елементів контейнеру, але з урахуванням маски: функція буде застосована тільки до тих компонентів масиву, індекси яких відповідають індексам з елементами true маски mask (за замовчуванням - всі компоненти). Зауваження: розмірність маски не повинна перевищувати розмірність даних, до яких вона застосовується; маска нульової розмірності означає застосування функції fn до всіх елементів.
int
Save(const char* fName, const_iterator first, const_iterator last, const valarray<bool>& mask = valarray<bool>(size_t(0)), const char* comm = "", size_t dens = 1) const
           Запис вмісту контейнера даних з інтервалу [first,last) у файл fName з коментарем comm та зі щільністю запису dens. Запис ведеться з урахуванням маски mask: будуть записані лише ті елементи, індекси яких відповідають індексам з елементами true маски (по замовчуванню - всі елементи). Зауваження: оскільки запис ведеться порціями {t,x1(t), x2(t),..., xn(t)}, то маска повинна мати розмірність не більшу за n+1, причому час t визначається самою першою компонентою маски; маска нульової розмірності означає запис всіх елементів. Замість цієї функції рекомендується використовувати режим автозапису. Повертає 0 - ок, 1 - нульова щільність запису, 2 - неможливо відкрити файл.
int
Save(const char* fName, const valarray<bool>& mask = valarray<bool>(size_t(0)), const char* comm = "", size_t dens = 1) const
           Запис вмісту контейнера даних у файл fName з коментарем comm та зі щільністю запису dens. Запис ведеться з урахуванням маски mask: будуть записані лише ті елементи, індекси яких відповідають індексам з елементами true маски (по замовчуванню - всі елементи). Зауваження: оскільки запис ведеться порціями {t,x1(t), x2(t),..., xn(t)}, то маска повинна мати розмірність не більшу за n+1, причому час t визначається самою першою компонентою маски; маска нульової розмірності означає запис всіх елементів. Замість цієї функції рекомендується використовувати режим автозапису. Повертає 0 - ок, 1 - нульова щільність запису, 2 - неможливо відкрити файл.
int
Save(const char* fName, const_iterator first, const_iterator last, const char* comm = "", size_t dens = 1) const
           Запис вмісту контейнера даних з інтервалу [first,last) у файл fName з коментарем comm та зі щільністю запису dens. Замість цієї функції рекомендується використовувати режим автозапису. Повертає 0 - ок, 1 - нульова щільність запису, 2 - неможливо відкрити файл.
int
Save(const char* fName, const char* comm = "", size_t dens = 1) const
           Запис вмісту контейнера даних у файл fName з коментарем comm та зі щільністю запису dens. Замість цієї функції рекомендується використовувати режим автозапису. Повертає 0 - ок, 1 - нульова щільність запису, 2 - неможливо відкрити файл.
int
Load(const char* fName, bool isReplace = false)
           Поповнення вмісту контейнера даних з файлу fName. Формат даних (символи-роздільники та маркер коментарів) у файлі має відповідати поточниму формату контейнера. Реальне поповнення відбувається з урахуванням щільності density. Параметр isReplace визначає чи дані будуть заміщені (true) у випадку співпадання ключів, чи добавлені (false). Повертає 0 - відбулося поповнення контейнеру, 1 - не відбулося поповнення контейнеру, 2 - неможливо відкрити файл.
int

Get(valarray<T_data>& x, const T_index& t) const
           Записує у змінну x значення, що знаходяться у контейнері для аргументу t. Повертає кількість знайдених для аргументу t елементів.

valarray<T_data>

Get(const T_index& t) const
           Повертає значення, що знаходяться у контейнері для аргументу t. Якщо даних за цим аргументом не знайдено, результат не визначений.

T_index

GetBangBang(valarray<T_data>& x, const T_index& t, bool isNearest = false) const
           Аналогічно функції Get(valarray<T_data>& x, const T_index& t), але якщо для t значень не знайдено, то повертається наближене значення, ключ якого не перевищує t. Якщо isNearest = true, то повертається те значення, ключ якого найближчий до t. Повертає різницю між найближчим аргументом, що знайдений у контейнері та тим, що вимагався.

valarray<T_data>

GetBangBang(const T_index& t, bool isNearest = false) const
           Аналогічно функції Get(const T_index& t), але якщо для t значень не знайдено, то повертається наближене значення, ключ якого не перевищує t. Якщо isNearest = true, то повертається те значення, ключ якого найближчий до t.

T_index

GetApproximation(valarray<T_data>& x, const T_index& t, size_t order = 1) const
           Аналогічно функції Get(valarray<T_data>& x, const T_index& t), але якщо для t значень не знайдено, то обчислюється наближене значення з порядком апроксимації order (1 - лінійна апроксимація, 0 - релейна лівоорієнтована). Повертає різницю між найближчим аргументом, що знайдений у контейнері та тим, що вимагався. Увага: функція може бути скомпільована лише у випадку співпадання типів T_index та T_data.

valarray<T_data>

GetApproximation(const T_index& t, size_t order = 1) const
           Аналогічно функції Get(const T_index& t), але якщо для t значень не знайдено, то обчислюється наближене значення з порядком апроксимації order (1 - лінійна апроксимація, 0 - релейна лівоорієнтована). Увага: функція може бути скомпільована лише у випадку співпадання типів T_index та T_data.

 

Наслідкові функції-члени класу multimap
begin, clear, count, empty, end, equal_range, erase, find, insert, key_comp, lower_bound, max_size, rbegin, rend, size, swap, upper_bound, value_comp

 

Опис

Результати наукових обчислень, як правило, надзвичайно об’ємні. Чого лише коштує промоделювати одновимірну функцію із збереженням отриманих точок! Раніше для цього створювали ланцюги із масивів значень, використовуючи динамічне виділення пам’яті. Нічого поганого в цьому нема, але пани Степанов (Stepanov) та Страустрап (Stroustrup), всупереч анонсованій НАН України кризі програмології, запропонували цілий набір контейнерів, які значно спрощують написання подібних програм. За основу пропонується взяти асоціативний контейнер multimap <T_index, valarray<T_data> >, що забезпечує роботу із блоками даних вигляду t, x1(t),...,xn(t), (n>=0), де t - аргумент (або індекс) типу T_index, x - n-вимірний вектор значень, елементи якого мають тип T_data. За замовчуванням T_index та T_data мають тип double. Контейнер multimap є частиною STL – стандартної бібліотеки шаблонів і компілюється сучасними С++ компіляторами. Його специфікації читайте, наприклад, у "The C++ Programming Language, third edition" (B.Stroustrup).

Представлений клас інкапсулює основні дії, необхідність в яких виникає при маніпуляціях із результатами наукових обчислень: додавання результатів у контейнер (поповнення контейнеру), функціональну обробку, зберігання у файл та очищення контейнеру. Цей клас зручно використовувати в якості вхідного параметру для функцій моделювання, інтегрування тощо.

Конструктор передбачає задання імені файлу, куди будуть записані результати при автозаписі та необов'язкову стрічку з коментарем (зовсім не вказуйте аргументи, якщо не плануєте запис у файл). Автозапис – це запуск функції Save() із деструктора. Тобто достатньо ініціалізувати змінну типу result_manager із заданням імені файлу і функцію Save() вже не треба викликати безпосередньо, бо вона сама зробить свою справу в кінці області видимості змінної типу result_manager. Автозапис можна відмінити при необхідності за допомогою прапорця autosave=false. Конструктор без аргументів також блокує автозапис.

Поповнення контейнеру результатів можна проводити за допомогою однієї з функцій Add() (рекомендується) або використовуючи стандартні функції поповнення контейнеру multimap. Регулювання щільності поповнення контейнеру здійснюється за допомогою безпосереднього присвоювання значення параметру density (тільки для використання із функцією Add()). Нульове значення параметру density призводить до ігнорування всіх записів у контейнер, значення 1, навпаки, призводить до запису всіх значень. При цьому передбачається, що всі вектори значень, які додаються у контейнер мають однакову розмірність (дозволяється також нульова розмірність - для зберігання множини аргументів).

Функція Get(valarray<T_data>& x, const T_index& t) записує у x значення, що знаходяться у контейнері для аргументу t. Функція GetApproximation(valarray<T_data>& x, const T_index& t, size_t order = 1) робить те саме, але якщо для t значень не знайдено, то обчислюється апроксимація (з порядком order) та повертається різниця між найближчим аргументом, що знайдений у контейнері та тим, що вимагався. Крім того, передбачені функції, які безпосередньо повертають занчення (без використання буферу x): Get(const T_index& t) та GetApproximation(const T_index& t, size_t order = 1). Схожим чином працюють функції GetBangBang(). Треба при цьому слідкувати, щоб, по-перше, контейнер не був порожнім, а по-друге, щоб у контейнері ключі (тобто аргументи) не повторювалися. Інакше треба використовувати функції-члени класу multimap.

Ось типове використання цього класу.

ResultManager results("res.txt");
results.Add(t, v); //додали в контейнер змінну типу valarray<double> з аргументом t
w = results.GetApproximation(t); //записали у змінну w типу valarray<double> значення, отримані для аргументу t

В результаті буде автоматично створений файл res.txt, у якому будуть міститися дані, що були накопичені під час роботи програми.

Також можна явно використати функцію Save(), для запису всіх або частини даних у файл. Читання з файлу записаної інформації здійснюється за допомогою Load(). Сервісні функції Modify() призначені для перетворювання даних, які містяться в контейнері. Якщо, наприклад, є необхідність змінити кожну компоненту всіх елементів контейнеру на їхні косинуси, то це можна здійснити за допомогою функції Modify(cos);  Якщо зміні підлягають тільки деякі компоненти, то необхідно використати маску (підставляючи true на місце тих компонентів, які необхідно змінити). Для простих перетворювань (розтягу та зсуву на константу) перевантажено відповідні оператори *=, /=, +=, -=.

Крім того, доцільно використовувати стандартні функції контейнеру multimap, такі як erase(), clear(), find(), size(), begin() тощо.

Декілька слів про файл збереження результатів. Перш за все, не варто гнатися за „бінарністю”. Приріст швидкодії мінімальний, зате втрачається кросплатформеність. Крім того, часто виникає необхідність безпосередньо зазирнути у такий файл. Отже доцільно робити його текстовим. На сьогодні існує велика кількість різноманітних табличних та графічних візуалізаторів, які передбачають задання вхідної інформації у текстовому файлі. Але формати розміщення текстової інформації у файлі не стандартизовані. Тому користувач сам повинен попіклуватися про те, щоб отриманий файл відповідав бажаному формату. Передбачається, що дані розміщуються блоками (аргумент та n значень, які йому відповідають) - кожен блок у окремій стрічці. Дані в середені блоку розділяються пробілами, але за допомогою змінної separator можна задавати додатковий символ-роздільник (наприклад, кому). Також дозволяються коментарі, які можна розташовувати на початку файлу. Кожна стрічка коментарів повинна починатися з деякого символа (маркера), який задається у remark_mark (за замовчуванням ';' - крапка з комою). Саме такий формат підтримує, зокрема, JEDIgviewer.

Приклад використання МДС знаходиться у файлі main.cpp у директорії mds_example. Додаткова інформація по використанню міститься в описі пакету.


Будь-ласка, надсилайте пропозиції, питання, зауваження: soft@unicyb.kiev.ua
Запрошуємо також до участі у самому проекті: надсилайте свої матеріали, які, по-можливості, будуть виставлені на сайті (див. Для авторів).

Кафедра Моделювання складних систем факультету кібернетики Київського університету імені Тараса Шевченка
03127, Україна, Київ, просп. Глушкова 2, корп. 6, кафедра МСС тел.: (044) 259-05-31, (044) 259-02-37, e-mail: garash@unicyb.kiev.ua
Всі права застережено.