Реферат паралельні методи множення матриці на вектор



Скачати 367.44 Kb.
Сторінка2/2
Дата конвертації09.11.2017
Розмір367.44 Kb.
ТипРеферат
1   2

2.3.4 Аналіз ефективності

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

Як вже відзначалося, алгоритм Фокса вимагає для свого виконання ітерацій, в ході яких кожен процесор перемножує свої поточні блоки матриць і та додає результати множення до поточного значення блоку матриці. З урахуванням висунених припущень загальна кількість виконуваних при цьому операцій матиме порядок . Як результат, показники прискорення і ефективності алгоритму мають вигляд.

Загальний аналіз складності знову дає ідеальні показники ефективності паралельних обчислень. Уточнимо отримані співвідношення - вкажемо для цього точнішу кількість обчислювальних операцій алгоритму і врахуємо витрати на виконання операцій передачі даних між процесорами.

Визначимо кількість обчислювальних операцій. Складність виконання скалярного множення рядка блоку матриці на стовпець блоку матриці можна оцінити як . Кількість рядків і стовпців у блоках рівна і, як результат, трудомісткість операції блокового множення виявляється рівною. Для складання блоків потрібні операцій. З урахуванням усіх перерахованих виразів час виконання обчислювальних операцій алгоритму Фокса може бути оцінений таким чином.

Оцінимо витрати на виконання операцій передачі даних між процесорами. На кожній ітерації алгоритму перед множенням блоків один з процесорів рядка процесорних грат розсилає свій блок матриці іншим процесорам свого рядка. Як вже відзначалося раніше, при топології мережі у вигляді гіперкуба або повного графа виконання цієї операції може бути забезпечене за кроків, а об'єм передаваних блоків рівний . Як результат, час виконання операції передачі блоків матриці при використанні моделі Хокни може оцінюватися як де - латентність, - пропускна спроможність мережі передачі даних, а є розмір елементу матриці у байтах. У разі ж, коли топологія рядків процесорних грат є кільцем, вираження для оцінки часу передачі блоків матриці набирає вигляду.

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

Підсумувавши усі отримані вирази, можна отримати, що загальний час виконання алгоритму Фокса може бути визначений за допомогою наступних співвідношень.


2.3.5 Програмна реалізація

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

1) Головна функція програми.

Визначає основну логіку роботи алгоритму, послідовно викликає необхідні підпрограми.

Програма 2.1
int ProcNum = 0; // Number of available processes

int ProcRank = 0; // Rank of current process

int GridSize; // Size of virtual processor grid

int GridCoords[2]; // Coordinates of current processor in grid

MPI_Comm GridComm; // Grid communicator

MPI_Comm ColComm; // Column communicator

MPI_Comm RowComm; // Row communicator

void main ( int argc, char * argv[] ) {

double* pAMatrix; // The first argument of matrix multiplication

double* pBMatrix; // The second argument of matrix multiplication

double* pCMatrix; // The result matrix

int Size; // Size of matricies

int BlockSize; // Sizes of matrix blocks on current process

double *pAblock; // Initial block of matrix A on current process

double *pBblock; // Initial block of matrix B on current process

double *pCblock; // Block of result matrix C on current process

double *pMatrixAblock;

double Start, Finish, Duration;

setvbuf(stdout, 0, _IONBF, 0);

MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &ProcNum);

MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);

GridSize = sqrt((double)ProcNum);

if (ProcNum != GridSize*GridSize) {

if (ProcRank == 0) {

printf ("Number of processes must be a perfect square \n");

}

}

else {



if (ProcRank == 0)

printf("Parallel matrix multiplication program\n");

// Creating the cartesian grid, row and column communcators

CreateGridCommunicators();

// Memory allocation and initialization of matrix elements

ProcessInitialization ( pAMatrix, pBMatrix, pCMatrix, pAblock, pBblock,

pCblock, pMatrixAblock, Size, BlockSize );

DataDistribution(pAMatrix, pBMatrix, pMatrixAblock, pBblock, Size,

BlockSize);

// Execution of Fox method

ParallelResultCalculation(pAblock, pMatrixAblock, pBblock,

pCblock, BlockSize);

ResultCollection(pCMatrix, pCblock, Size, BlockSize);

TestResult(pAMatrix, pBMatrix, pCMatrix, Size);

// Process Termination

ProcessTermination (pAMatrix, pBMatrix, pCMatrix, pAblock, pBblock,

pCblock, pMatrixAblock);

}

MPI_Finalize();}


2) Функція CreateGridCommunicators.

Ця функція створює комунікатор у вигляді двовимірних квадратних грат, визначає координати кожного процесу в цих гратах, а також створює комунікатори окремо для кожного рядка і кожного стовпця.

Створення грат робиться за допомогою функції MPI _ Cart _ create(вектор Periodic визначає можливість передачі повідомлень між граничними процесами рядків і стовпців створюваних грат). Після створення грат кожен процес паралельної програми матиме координати свого положення в гратах; отримання цих координат забезпечується за допомогою функції MPI _ Cart _ coords.

Формування топологій завершується створенням безлічі комунікаторів для кожного рядка і кожного стовпця грат окремо(функція MPI _ Cart _ sub).


// Creation of two-dimensional grid communicator

// and communicators for each row and each column of the grid

void CreateGridCommunicators() {

int DimSize[2]; // Number of processes in each dimension of the grid

int Periodic[2]; // =1, if the grid dimension should be periodic

int Subdims[2]; // =1, if the grid dimension should be fixed

DimSize[0] = GridSize;

DimSize[1] = GridSize;

Periodic[0] = 0;

Periodic[1] = 0;

// Creation of the Cartesian communicator

MPI_Cart_create(MPI_COMM_WORLD, 2, DimSize, Periodic, 1, &GridComm);

// Determination of the cartesian coordinates for every process

MPI_Cart_coords(GridComm, ProcRank, 2, GridCoords);

// Creating communicators for rows

Subdims[0] = 0; // Dimensionality fixing

Subdims[1] = 1; // The presence of the given dimension in the subgrid

MPI_Cart_sub(GridComm, Subdims, &RowComm);

// Creating communicators for columns

Subdims[0] = 1;

Subdims[1] = 0;

MPI_Cart_sub(GridComm, Subdims, &ColComm);


3) Функція ProcessInitialization.

Для визначення розмірів матриць і матричних блоків, виділення пам'яті для їх зберігання і визначення елементів початкових матриць реалізується функція ProcessInitialization.

Ця функція визначає параметри вирішуваної задачі(розміри матриць і їх блоків), виділяє пам'ять для зберігання даних і здійснює введення початкових матриць(чи формує їх за допомогою якого-небудь датчика випадкових чисел). Всього в кожному процесі має бути виділена пам'ять для зберігання чотирьох блоків - для покажчиків використовуються змінні pAblock, pBblock, pCblock, pMatrixAblock. Перші три покажчики визначають блоки матриць, і відповідно. Слід зазначити, що вміст блоків pAblock і pBblock постійно змінюється відповідно до пересилки даних між процесами, тоді як блок pMatrixAblock матриці залишається незмінним і використовується при розсилках блоків по рядках грат процесів(див. функцію AblockCommunication).
// Function for memory allocation and data initialization

void ProcessInitialization (double* &pAMatrix, double* &pBMatrix,

double* &pCMatrix, double* &pAblock, double* &pBblock, double* &pCblock,

double* &pTemporaryAblock, int &Size, int &BlockSize ) {

if (ProcRank == 0) {

do {


printf("\nEnter size of the initial objects: ");

scanf("%d", &Size);

if (Size%GridSize != 0) {

printf ("Size of matricies must be divisible by the grid size! \n");

}

}

while (Size%GridSize != 0);



}

MPI_Bcast(&Size, 1, MPI_INT, 0, MPI_COMM_WORLD);

BlockSize = Size/GridSize;

pAblock = new double [BlockSize*BlockSize];

pBblock = new double [BlockSize*BlockSize];

pCblock = new double [BlockSize*BlockSize];


pTemporaryAblock = new double [BlockSize*BlockSize];

for (int i=0; i

pCblock[i] = 0;

}

if (ProcRank == 0) {



pAMatrix = new double [Size*Size];

pBMatrix = new double [Size*Size];

pCMatrix = new double [Size*Size];

RandomDataInitialization(pAMatrix, pBMatrix, Size);

}

}

4) Функція DataDistribution для розподілу початкових даних і функція ResultCollection для збору результатів.



Після задання початкових матриць на нульовому процесі необхідно здійснити розподіл початкових даних. Для цього призначена функція DataDistribution. Можуть бути запропоновані два способи виконання блокового розділення матриць між процесорами, організованими в двовимірні квадратні грати. З одного боку, для організації передачі блоків у рамках однієї і тієї ж комунікаційної операції можна сформувати засобами MPI похідний тип даних. З іншого боку, можна організувати двохетапну процедуру. На першому етапі матриця розділяється на горизонтальні смуги. Ці смуги розподіляються на процеси, що складають нульовий стовпець процесорних грат. Далі кожна смуга розділяється на блоки між процесами, що становлять рядки процесорних грат.

Для виконання збору результуючої матриці з блоків призначена функція ResultCollection. Збір даних також виконати двома способами: або з використанням похідного типу даних, або за допомогою двоетапної процедури, що дзеркально відображає процедуру розподілу матриці.

Реалізація функцій DataDistribution і ResultCollection є завданням для самостійної роботи.

5) Функція AblockCommunication обміну блоками матриці A.

Функція виконує розсилку блоків матриці по рядках процесорних грат. Для цього в кожному рядку грат визначається провідний процес Pivot, що здійснює розсилку. Для розсилки використовується блок pMatrixAblock, переданий в процес у момент початкового розподілу даних. Виконання операції розсилки блоків здійснюється за допомогою функції MPI _ Bcast. Слід зазначити, що ця операція є колективною і її локалізація межами окремих рядків грат забезпечується за рахунок використання комунікаторів RowComm, визначених для набору процесів кожного рядка грат окремо.
// Broadcasting matrix A blocks to process grid rows

int BlockSize) {

// Defining the leading process of the process grid row

int Pivot = (GridCoords[0] + iter) % GridSize;

// Copying the transmitted block in a separate memory buffer

if (GridCoords[1] == Pivot) {

for (int i=0; i

pAblock[i] = pMatrixAblock[i];

} // Block broadcasting

MPI_Bcast(pAblock, BlockSize*BlockSize, MPI_DOUBLE, Pivot, RowComm);

}

6) Функція перемножування матричних блоків BlockMultiplication.



Функція забезпечує перемножування блоків матриць і . Слід зазначити, що для легшого розуміння даної програми наводиться простий варіант реалізації функції - виконання операції блокового множення може бути істотним чином оптимізовано для скорочення часу обчислень. Ця оптимізація може бути спрямована, наприклад, на підвищення ефективності використання кешу процесорів, векторизації виконуваних операцій і тому подібне:
// Множення матричних блоків

void BlockMultiplication (double *pAblock, double *pBblock,

double *pCblock, int BlockSize) {

// вычисление произведения матричных блоков

for (int i=0; i

for (int j=0; j

double temp = 0;

for (int k=0; k

temp += pAblock [i*BlockSize + k] * pBblock [k*BlockSize + j]

pCblock [i*BlockSize + j] += temp;

}

}

}



7) Функція BblockCommunication обміну блоками матриці B.

Функція виконує циклічне зрушення блоків матриці по стовпцях процесорних грат. Кожен процес передає свій блок наступному процесу NextProc у стовпці процесів і отримує блок, переданий з попереднього процесу PrevProc в стовпці грат. Виконання операцій передачі даних здійснюється за допомогою функції MPI _ SendRecv _ replace, яка забезпечує усі необхідні пересилки блоків, використовуючи при цьому один і той же буфер пам'яті pBblock. Крім того, ця функція гарантує відсутність можливої безвиході, коли операції передачі даних починають одночасно виконуватися декількома процесами при кільцевій топології мережі.

// Cyclic shift of matrix B blocks in the process grid columns

void BblockCommunication (double *pBblock, int BlockSize) {

MPI_Status Status;

int NextProc = GridCoords[0] + 1;

if ( GridCoords[0] == GridSize-1 ) NextProc = 0;

int PrevProc = GridCoords[0] - 1;

if ( GridCoords[0] == 0 ) PrevProc = GridSize-1;

MPI_Sendrecv_replace( pBblock, BlockSize*BlockSize, MPI_DOUBLE,

NextProc, 0, PrevProc, 0, ColComm, &Status);

}

8) Функція ParallelResultCalculation.



Для безпосереднього виконання паралельного алгоритму Фокса множення матриць призначена функція ParallelResultCalculation, яка реалізує логіку роботи алгоритму.
void ParallelResultCalculation(double* pAblock, double* pMatrixAblock,

double* pBblock, double* pCblock, int BlockSize) {

for (int iter = 0; iter < GridSize; iter ++) {

// Sending blocks of matrix A to the process grid rows

ABlockCommunication (iter, pAblock, pMatrixAblock, BlockSize);

// Block multiplication

BlockMultiplication(pAblock, pBblock, pCblock, BlockSize);

// Cyclic shift of blocks of matrix B in process grid columns

BblockCommunication(pBblock, BlockSize);

}

}


2.3.6 Результати обчислювальних експериментів

Обчислювальні експерименти для оцінки ефективності паралельного алгоритму проводилися за тих же умов. Результати експериментів з використанням чотирьох і дев'яти процесорів приведені в таблиці 2.3.


Таблиця 2.3 Результатів обчислювальних експериментів по дослідженню паралельного алгоритму Фокса:

Розмір матриці

Послідовний алгоритм

Паралельний алгоритм










4 ЦП

9 ЦП







Час

Присокрення

Час

Присокрення

500

0,8527

0,2190

3,8925

0,1468

5,8079

1000

12,8787

3,0910

4,1664

2,1565

5,9719

1500

43,4731

10,8678

4,0001

7,2502

5,9960

2000

103,0561

24,1421

4,2687

21,4157

4,8121

2500

201,2915

51,4735

3,9105

41,2159

4,8838

3000

347,8434

87,0538

3,9957

58,2022

5,9764

Порівняння часу виконання експерименту і теоретичного часу , обчислено і представлено в таблиці 2.4.

Таблиця 2.4 Порівняння експериментального і теоретичного часу виконання паралельного алгоритму Фокса.

Розмір матриці

Паралельний алгоритм










4 ЦП

9 ЦП



















500

0,4217

0,2190

0,2200

0,1468

1000

3,2970

3,0910

1,5924

2,1565

1500

11,0419

10,8678

5,1920

7,2502

2000

26,0726

24,1421

12,0927

21,4157

2500

50,8049

51,4735

23,3682

41,2159

3000

87,6548

87,0538

40,0923

58,2022



2.4 Алгоритм Кэннона множення матриць при блоковому розділенні даних
Розглянемо ще один паралельний алгоритм матричного множення, грунтований на блоковому розбитті матриць.
2.4.1 Визначення підзадач

Як і при розгляді алгоритму Фокса, в якості базової підзадачі виберемо обчислення, пов'язані з визначенням одного з блоків результуючої матриці . Як вже відзначалося раніше, для обчислення елементів цього блоку підзадача повинна мати доступ до елементів горизонтальної смуги матриці і до елементів вертикальної смуги матриці .


2.4.2 Виділення інформаційних залежностей

Відмінність алгоритму Кэннона від представленого в попередньому підрозділі методу Фокса полягає в зміні схеми початкового розподілу блоків перемножуваних матриць між підзадачами обчислювальної системи. Початкове розташування блоків в алгоритмі Кэннона підбирається так, щоб блоки, які розташовуються, в підзадачах могли б бути перемножені без додаткового обміну даними. При цьому подібний розподіл блоків може бути організований таким чином, що переміщення блоків між підзадачами в ході обчислень може здійснюватися з використанням простіших комунікаційних операцій.

Зважаючи на висловлені зауваження етап ініціалізації алгоритму Кэннона включає виконання наступних операцій обміну даними :


  • у кожну підзадачу(i, j) передаються блоки Aij, Bij;

  • для кожного рядка i грат підзадач блоки матриці A зрушуються на(i - 1) позицій вліво;

  • для кожного стовпця j грат підзадач блоки матриці B зрушуються на(j - 1) позицій вгору.

Перерозподіл блоків матриць A и В

В результаті такого початкового розподілу в кожній базовій підзадачі розташовуватимуться блоки, які можуть бути перемножені без додаткового обміну даними. Крім того, отримання усіх подальших блоків для підзадач може бути забезпечене за допомогою простих комунікаційних дій. Після виконання операції блокового множення кожен блок матриці має бути переданий попередній підзадачі вліво по рядках грат підзадач, а кожен блок матриці - попередній підзадачі вгору по стовпцях грат. Послідовність таких циклічних зрушень і множення отримуваних блоків початкових матриць і приведе до отримання у базових підзадачах відповідних блоків результуючої матриці .


2.4.3 Масштабування і розподіл підзадач по процесорах

Як і раніше в методі Фокса, для алгоритму Кэннона розмір блоків може бути підібраний так, щоб кількість базових підзадач співпадала з числом наявних процесорів. Оскільки об'єм обчислень в кожній підзадачі є однаковим, це забезпечує повне балансування обчислювального навантаження між процесорами.

Для розподілу підзадач між процесорами може бути застосований підхід, використаний в алгоритмі Фокса, - безліч наявних процесорів представляється у вигляді квадратних грат і розміщення базових підзадач здійснюється на процесорах відповідних вузлів процесорних грат. Необхідна структура мережі передачі даних, як і раніше, може бути забезпечена на фізичному рівні при топології обчислювальної системи у вигляді грат або повного графа.
2.4.4 Аналіз ефективності

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

Відповідно до правил алгоритму на етапі ініціалізації робиться перерозподіл блоків матриць і за допомогою циклічного зрушення матричних блоків по рядках і стовпцях процесорних грат. Трудомісткість виконання такої операції передачі даних істотним чином залежить від топології мережі. Для мережі із структурою повного графа усі необхідні пересилки блоків можуть бути виконані одночасно(тобто тривалість операції виявляється рівною часу передачі одного матричного блоку між сусідніми процесорами). Для мережі з топологією гіперкуба операція циклічного зрушення може потребувати виконання ітерацій. Для мережі з кільцевою структурою зв'язків необхідна кількість ітерацій виявляється рівною . Детальніше методи виконання операції циклічного зрушення розглянуті в розділі 3. Для побудови оцінки комунікаційної складності етапу ініціалізації використовується варіант топології повного графа. Час виконання початкового перерозподілу блоків може оцінюватися.

(вираз визначає розмір блоків, що пересилаються, а коефіцієнт 2 відповідає двом виконуваним операціям циклічного зрушення).

Оцінимо тепер витрати на передачу даних між процесорами при виконанні основної частини алгоритму Кэннона. На кожній ітерації алгоритму після множення матричних блоків процесори передають свої блоки попереднім процесорам по рядках(для блоків матриці ) і стовпцях (для блоків матриці ) процесорних грат. Ці операції також можуть бути виконані процесорами паралельно і, тим самим, тривалість таких комунікаційних дій складає.

Оскільки кількість ітерацій алгоритму Кэннона являється рівним q, то з урахуванням оцінки загальний час виконання паралельних обчислень може бути визначений за допомогою наступного співвідношення:


2.4.5 Результати обчислювальних експериментів

Обчислювальні експерименти для оцінки ефективності паралельного алгоритму проводилися за тих же умов, що і раніше виконані експерименти. Результати експериментів для випадків чотирьох і дев'яти процесорів приведені в таблиці 2.5.


Таблиця 2.5 Результатів обчислювальних експериментів по дослідженню паралельного алгоритму Кэннона.

Розмір об’єктів

Послідовний алгоритм

Паралельний алгоритм










4 ЦП

9 ЦП







Час

Присокрення

Час

Присокрення

1000

12,8787

3,0806

4,1805

1,1889

10,8324

1500

43,4731

11,1716

3,8913

4,6310

9,3872

2000

103,0561

24,0502

4,2850

14,4759

7,1191

2500

201,2915

53,1444

3,7876

23,5398

8,5511

3000

347,8434

88,2979

3,9394

36,3688

9,5643

З результатів наведених в таблиці, можна зробити аналіз алгоритму на ефективність, а порівнянні з іншими алгоритмами.



ВИСНОВОК
У даній курсовій роботі розглянуті три паралельні методи для виконання операції матричного множення. Перший алгоритм грунтований на стрічковому розділенні матриць між процесорами. У роботі приведені два різні варіанти цього алгоритму. Перший варіант алгоритму грунтований на різному розділенні перемножуваних матриць - перша матриця (матриця ) розбивається на горизонтальні смуги, а друга матриця (матриця ) ділиться на вертикальні смуги. Другий варіант стрічкового алгоритму використовує розбиття обох матриць на горизонтальні смуги.

Далі в роботі розглядаються широко відомі алгоритми Фокса і Кэннона, грунтовані на блоковому розділенні матриць. При використанні однакової схеми розбиття матриць ці алгоритми відрізняються характером виконуваних операцій передачі даних. Для алгоритму Фокса в ході обчислень здійснюється розсилка і циклічне зрушення блоків матриць, в алгоритмі Кэннона виконується тільки операція циклічного зрушення.

Відмінність в способах розбиття даних призводить до різних топологій комунікаційної мережі, при яких виконання паралельних алгоритмів є найбільш ефективним. Так, алгоритми, грунтовані на стрічковому розділенні даних, орієнтовані на топологію мережі у вигляді гіперкуба або повного графа. Для реалізації алгоритмів, грунтованих на блоковому розділенні даних, потрібна наявність топології грат.

На загальному графіку представлені показники прискорення, отримані в результаті виконання обчислювальних експериментів для усіх розглянутих алгоритмів. Як можна помітити, при використанні чотирьох процесорів деяку перевагу по прискоренню має паралельний алгоритм при стрічковому розділенні даних. Виконані розрахунки показують також, що при більшій кількості процесорів ефективнішими стають блокові алгоритми множення матриць.



СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ
1. Гергель, В.П., Стронгин, Р.Г. (2001). Основы параллельных вычислений для многопроцессорных вычислительных систем. - Н.Новгород, ННГУ (2 изд., 2003).

2. Culler, D.E., et al. (1996). LogP: A practical model for parallel computation. – Comm. Of the ACM, 39, 11, pp. 75-85.

3. Hockney, R. (1994). The communication challenge for MPP: Intel Paragon and Meiko CS-2. – Parallel Computing, 20 (3), pp. 389-398.

4. Kumar V., Grama, A., Gupta, A., Karypis, G. (1994). Introduction to Parallel Computing. - The Benjamin/Cummings Publishing Company, Inc. (2nd edn., 2003)

5. Quinn, M. J. (2004). Parallel Programming in C with MPI and OpenMP. – New York, NY: McGraw-Hill.

6. Skillicorn, D.B., Talia, D. (1998). Models and languages for parallel computation. – ACM Computing surveys, 30, 2.




Каталог: uploads -> 877173f1-52e0-4a1f-a4ae-d078558a1aa4
uploads -> Правила прийому до аспірантури та докторантури київського національного університету культури І мистецтв
uploads -> Положення про аспірантуру Миколаївського національного університету імені В. О. Сухомлинського Загальна частина
uploads -> Програма дисципліни «іноземна мова (англійська)»
uploads -> Положення правил прийому до нту "хпі" на 2016 рік правила прийому 2016 Організацію прийому до нту "хпі" та його структурних підрозділів здійснює приймальна комісія правила прийому 2016
uploads -> Програма та методичні вказівки з навчальної дисципліни історія науки І техніки для студентів усіх спеціальностей денної форми навчання
uploads -> Лекція № Тема лекції: Поняття мистецтва як частини культури
uploads -> Афінська держава та стародавня спарта у стародавній історії та культурі людства
uploads -> Київський національний лінгвістичний університет базові навчально-методичні матеріали
uploads -> Освіта осіб з інвалідністю в Україні Тематична національна доповідь Київ -2010 Тематичну національну доповідь «Освіта осіб з інвалідністю в Україні»
877173f1-52e0-4a1f-a4ae-d078558a1aa4 -> Перелік умовних позначень, символів, одиниць, скорочень І термінів

Скачати 367.44 Kb.

Поділіться з Вашими друзьями:
1   2




База даних захищена авторським правом ©uchika.in.ua 2020
звернутися до адміністрації

    Головна сторінка