You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

486 lines
25 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

% ===============================================
% ДЕМОНСТРАЦИЯ LAB9 TASK2
% Полная демонстрация специальных предикатов
% ===============================================
% Главная демонстрация
demo :-
write('=== ДЕМОНСТРАЦИЯ LAB9 TASK2: СПЕЦИАЛЬНЫЕ ПРЕДИКАТЫ PROLOG ==='), nl, nl,
% 1. Демонстрация произведения цифр
write('1. ПРОИЗВЕДЕНИЕ ЦИФР ЧИСЛА'), nl,
write('==========================='), nl,
demo_digit_product,
nl,
% 2. Демонстрация максимальной цифры не делящейся на 3
write('2. МАКСИМАЛЬНАЯ ЦИФРА НЕ ДЕЛЯЩАЯСЯ НА 3'), nl,
write('======================================='), nl,
demo_max_digit_not_div3,
nl,
% 3. Демонстрация количества делителей
write('3. КОЛИЧЕСТВО ДЕЛИТЕЛЕЙ ЧИСЛА'), nl,
write('============================='), nl,
demo_divisor_count,
nl,
% 4. Сравнительный анализ рекурсий
write('4. СРАВНИТЕЛЬНЫЙ АНАЛИЗ РЕКУРСИЙ'), nl,
write('================================'), nl,
demo_recursion_comparison,
nl,
% 5. Анализ унификации переменных
write('5. АНАЛИЗ УНИФИКАЦИИ ПЕРЕМЕННЫХ'), nl,
write('==============================='), nl,
demo_unification_analysis,
nl,
% 6. Практические примеры
write('6. ПРАКТИЧЕСКИЕ ПРИМЕРЫ'), nl,
write('======================='), nl,
demo_practical_examples,
nl,
% 7. Производительность и оптимизация
write('7. ПРОИЗВОДИТЕЛЬНОСТЬ И ОПТИМИЗАЦИЯ'), nl,
write('==================================='), nl,
demo_performance_analysis,
nl,
write('=== ДЕМОНСТРАЦИЯ TASK2 ЗАВЕРШЕНА ==='), nl.
% -----------------------------------------------
% Демонстрация произведения цифр
% -----------------------------------------------
demo_digit_product :-
write('Предикаты digit_product_up/2 и digit_product_down/2 вычисляют'), nl,
write('произведение всех цифр числа.'), nl, nl,
write('ПРИНЦИП РАБОТЫ:'), nl,
write('- digit_product_up: рекурсия вверх, вычисления при возврате'), nl,
write('- digit_product_down: рекурсия вниз с аккумулятором'), nl, nl,
TestNumbers = [0, 1, 123, 456, 789, 102, 555, 12345],
write('Сравнение результатов:'), nl,
write('Число | Произведение (вверх) | Произведение (вниз) | Время (вверх) | Время (вниз)'), nl,
write('--------|----------------------|---------------------|---------------|-------------'), nl,
forall(member(N, TestNumbers), demo_digit_product_case(N)),
nl,
write('ОСОБЫЕ СЛУЧАИ:'), nl,
write('- Произведение цифр 0 = 1 (по определению)'), nl,
write('- Если число содержит 0, произведение = 0'), nl,
write('- Для однозначных чисел произведение = само число'), nl, nl,
write('ДЕМОНСТРАЦИЯ УНИФИКАЦИИ для digit_product_up(123, P):'), nl,
write('1. N=123 (унифицированная), P - неунифицированная'), nl,
write('2. Digit = 123 mod 10 = 3 (унифицируется)'), nl,
write('3. N1 = 123 // 10 = 12 (унифицируется)'), nl,
write('4. Рекурсивный вызов digit_product_up(12, SubProduct)'), nl,
write('5. SubProduct = 2 (унифицируется при возврате)'), nl,
write('6. P = 3 * 2 = 6 (унифицируется с результатом)'), nl.
demo_digit_product_case(N) :-
get_time(T1),
digit_product_up(N, P1),
get_time(T2),
digit_product_down(N, P2),
get_time(T3),
TimeUp is T2 - T1,
TimeDown is T3 - T2,
format('~w~7| | ~w~19| | ~w~18| | ~6f~9| | ~6f~n', [N, P1, P2, TimeUp, TimeDown]).
% -----------------------------------------------
% Демонстрация максимальной цифры не делящейся на 3
% -----------------------------------------------
demo_max_digit_not_div3 :-
write('Предикаты max_digit_not_div3_up/2 и max_digit_not_div3_down/2'), nl,
write('находят максимальную цифру числа, которая не делится на 3.'), nl, nl,
write('ПРИНЦИП РАБОТЫ:'), nl,
write('- Проверяем каждую цифру на деление на 3'), nl,
write('- Среди не делящихся на 3 находим максимальную'), nl,
write('- Если все цифры делятся на 3, возвращаем -1'), nl, nl,
TestNumbers = [0, 123, 456, 789, 369, 147, 98765, 36960, 12457],
write('Анализ цифр по числам:'), nl,
write('Число | Цифры | Не дел. на 3 | Максимум (вверх) | Максимум (вниз)'), nl,
write('--------|------------|--------------|------------------|----------------'), nl,
forall(member(N, TestNumbers), demo_max_digit_case(N)),
nl,
write('ОБЪЯСНЕНИЕ РЕЗУЛЬТАТОВ:'), nl,
write('- 123: цифры [1,2,3], не дел. на 3: [1,2] → макс: 2'), nl,
write('- 369: цифры [3,6,9], все делятся на 3 → результат: -1'), nl,
write('- 147: цифры [1,4,7], не дел. на 3: [1,4,7] → макс: 7'), nl, nl,
write('ДЕМОНСТРАЦИЯ УНИФИКАЦИИ для max_digit_not_div3_up(147, M):'), nl,
write('1. N=147 (унифицированная), M - неунифицированная'), nl,
write('2. Digit = 147 mod 10 = 7 (унифицируется)'), nl,
write('3. N1 = 147 // 10 = 14 (унифицируется)'), nl,
write('4. Рекурсивный вызов max_digit_not_div3_up(14, SubMax)'), nl,
write('5. SubMax = 4 (унифицируется при возврате)'), nl,
write('6. combine_max_not_div3(7, 4, M): 7 не дел. на 3, M = max(7,4) = 7'), nl.
demo_max_digit_case(N) :-
% Получаем список цифр
number_digits(N, Digits),
% Фильтруем не делящиеся на 3
include(not_divisible_by_3, Digits, NotDiv3),
max_digit_not_div3_up(N, M1),
max_digit_not_div3_down(N, M2),
format('~w~7| | ~w~9| | ~w~11| | ~w~15| | ~w~n', [N, Digits, NotDiv3, M1, M2]).
% Вспомогательные предикаты для демонстрации
number_digits(0, [0]) :- !.
number_digits(N, Digits) :-
N > 0,
number_digits_helper(N, [], Digits).
number_digits_helper(0, Acc, Acc) :- !.
number_digits_helper(N, Acc, Digits) :-
N > 0,
Digit is N mod 10,
N1 is N // 10,
number_digits_helper(N1, [Digit|Acc], Digits).
not_divisible_by_3(Digit) :-
Digit mod 3 =\= 0.
% -----------------------------------------------
% Демонстрация количества делителей
% -----------------------------------------------
demo_divisor_count :-
write('Предикаты для подсчета количества делителей числа:'), nl,
write('- divisor_count_up/2: рекурсия вверх'), nl,
write('- divisor_count_down/2: рекурсия вниз с аккумулятором'), nl,
write('- divisor_count_optimized/2: оптимизированный алгоритм'), nl, nl,
write('ПРИНЦИП ОПТИМИЗАЦИИ:'), nl,
write('- Обычный алгоритм: проверяем все числа от 1 до N'), nl,
write('- Оптимизированный: проверяем только до sqrt(N)'), nl,
write('- Для каждого делителя d находим пару N/d'), nl,
write('- Если d = sqrt(N), добавляем только один раз'), nl, nl,
TestNumbers = [1, 6, 12, 24, 36, 100, 144, 1000],
write('Сравнение методов:'), nl,
write('Число | Делители | Кол-во | Время (up) | Время (down) | Время (opt)'), nl,
write('------|-------------------------------|--------|------------|--------------|------------'), nl,
forall(member(N, TestNumbers), demo_divisor_case(N)),
nl,
write('АНАЛИЗ СЛОЖНОСТИ:'), nl,
write('- Обычный алгоритм: O(N) - проверяем все числа до N'), nl,
write('- Оптимизированный: O(sqrt(N)) - проверяем только до sqrt(N)'), nl,
write('- Для N=10000: обычный ~10000 операций, оптим. ~100 операций'), nl, nl,
write('ДЕМОНСТРАЦИЯ УНИФИКАЦИИ для divisor_count_down(12, C):'), nl,
write('1. N=12 (унифицированная), C - неунифицированная'), nl,
write('2. Вызов helper(12, 1, 0, C)'), nl,
write('3. Current=1, Acc=0: 12 mod 1 = 0 → Acc1 = 1'), nl,
write('4. Current=2, Acc=1: 12 mod 2 = 0 → Acc1 = 2'), nl,
write('5. Current=3, Acc=2: 12 mod 3 = 0 → Acc1 = 3'), nl,
write('6. Current=4, Acc=3: 12 mod 4 = 0 → Acc1 = 4'), nl,
write('7. Current=5, Acc=4: 12 mod 5 ≠ 0 → Acc1 = 4'), nl,
write('8. Current=6, Acc=4: 12 mod 6 = 0 → Acc1 = 5'), nl,
write('9. Current=7..11: не делители → Acc1 = 5'), nl,
write('10. Current=12, Acc=5: 12 mod 12 = 0 → Acc1 = 6'), nl,
write('11. Current=13 > 12 → C унифицируется с 6'), nl.
demo_divisor_case(N) :-
% Находим все делители для отображения
findall(D, (between(1, N, D), N mod D =:= 0), Divisors),
get_time(T1),
divisor_count_up(N, C1),
get_time(T2),
divisor_count_down(N, C2),
get_time(T3),
divisor_count_optimized(N, C3),
get_time(T4),
TimeUp is T2 - T1,
TimeDown is T3 - T2,
TimeOpt is T4 - T3,
format('~w~5| | ~w~28| | ~w~6| | ~6f~4| | ~6f~6| | ~6f~n',
[N, Divisors, C1, TimeUp, TimeDown, TimeOpt]).
% -----------------------------------------------
% Сравнительный анализ рекурсий
% -----------------------------------------------
demo_recursion_comparison :-
write('Сравнение эффективности рекурсии вверх и вниз:'), nl, nl,
write('ТЕОРЕТИЧЕСКИЕ РАЗЛИЧИЯ:'), nl,
write('┌─────────────────┬──────────────────────┬────────────────────────┐'), nl,
write('│ Характеристика │ Рекурсия вверх │ Рекурсия вниз │'), nl,
write('├─────────────────┼──────────────────────┼────────────────────────┤'), nl,
write('│ Стек вызовов │ Растет с глубиной │ Оптимизируется │'), nl,
write('│ Вычисления │ При возврате │ При погружении │'), nl,
write('│ Память │ O(глубина) │ O(1) для хвост. рек. │'), nl,
write('│ Понимание │ Интуитивно │ Требует практики │'), nl,
write('│ Оптимизация │ Ограничена │ Компилятор может помочь│'), nl,
write('└─────────────────┴──────────────────────┴────────────────────────┘'), nl, nl,
write('ПРАКТИЧЕСКОЕ СРАВНЕНИЕ:'), nl,
TestNumbers = [12345, 987654, 1234567],
forall(member(N, TestNumbers), demo_recursion_performance(N)),
nl,
write('ВЫВОДЫ:'), nl,
write('1. Для небольших чисел разница незначительна'), nl,
write('2. Для больших чисел рекурсия вниз может быть эффективнее'), nl,
write('3. Рекурсия вниз безопаснее при глубокой рекурсии'), nl,
write('4. Оптимизированные алгоритмы дают наибольшее ускорение'), nl.
demo_recursion_performance(N) :-
write('Тестирование для N = '), write(N), write(':'), nl,
% Произведение цифр
get_time(T1),
digit_product_up(N, P1),
get_time(T2),
digit_product_down(N, P2),
get_time(T3),
TimeProductUp is T2 - T1,
TimeProductDown is T3 - T2,
write(' Произведение цифр: рекурсия вверх = '), write(TimeProductUp), write('с, '),
write('рекурсия вниз = '), write(TimeProductDown), write('с'), nl,
% Максимальная цифра
get_time(T4),
max_digit_not_div3_up(N, M1),
get_time(T5),
max_digit_not_div3_down(N, M2),
get_time(T6),
TimeMaxUp is T5 - T4,
TimeMaxDown is T6 - T5,
write(' Макс. цифра: рекурсия вверх = '), write(TimeMaxUp), write('с, '),
write('рекурсия вниз = '), write(TimeMaxDown), write('с'), nl, nl.
% -----------------------------------------------
% Анализ унификации переменных
% -----------------------------------------------
demo_unification_analysis :-
write('АНАЛИЗ УНИФИКАЦИИ В ПРЕДИКАТАХ:'), nl, nl,
write('1. ТИПЫ ПЕРЕМЕННЫХ В PROLOG:'), nl,
write(' • Унифицированные (+): уже имеют значение при вызове'), nl,
write(' • Неунифицированные (-): получают значение в процессе выполнения'), nl,
write(' • Переменные режима (?): могут быть и теми, и другими'), nl, nl,
write('2. ПРИМЕРЫ УНИФИКАЦИИ В НАШИХ ПРЕДИКАТАХ:'), nl, nl,
% Пример 1: digit_product_up
write('ПРИМЕР 1: digit_product_up(+N, -Product)'), nl,
write('Вызов: digit_product_up(123, P)'), nl,
write('• N = 123 (унифицированная при вызове)'), nl,
write('• Product = неунифицированная переменная'), nl,
write('• Digit is N mod 10 → Digit унифицируется с 3'), nl,
write('• N1 is N // 10 → N1 унифицируется с 12'), nl,
write('• При возврате из рекурсии SubProduct унифицируется с 2'), nl,
write('• Product is 3 * 2 → Product унифицируется с 6'), nl, nl,
% Пример 2: max_digit_not_div3_down
write('ПРИМЕР 2: max_digit_not_div3_down(+N, -MaxDigit)'), nl,
write('Вызов: max_digit_not_div3_down(147, M)'), nl,
write('• N = 147, M = неунифицированная'), nl,
write('• Вызов helper(147, -1, M) → CurrentMax = -1 (унифицированная)'), nl,
write('• Digit = 7, update_max_not_div3(7, -1, NewMax)'), nl,
write('• 7 mod 3 ≠ 0, CurrentMax = -1 → NewMax унифицируется с 7'), nl,
write('• Процесс продолжается с NewMax = 7 (теперь унифицированная)'), nl, nl,
% Пример 3: divisor_count_optimized
write('ПРИМЕР 3: divisor_count_optimized(+N, -Count)'), nl,
write('Вызов: divisor_count_optimized(16, C)'), nl,
write('• N = 16, C = неунифицированная'), nl,
write('• Sqrt is floor(sqrt(16)) → Sqrt унифицируется с 4'), nl,
write('• Current = 1: 16 mod 1 = 0, Current ≠ sqrt(16) → Acc1 = 0 + 2 = 2'), nl,
write('• Current = 2: 16 mod 2 = 0, Current ≠ sqrt(16) → Acc1 = 2 + 2 = 4'), nl,
write('• Current = 4: 16 mod 4 = 0, Current = sqrt(16) → Acc1 = 4 + 1 = 5'), nl,
write('• Current = 5 > Sqrt → C унифицируется с 5'), nl, nl,
write('3. ВАЖНЫЕ ОСОБЕННОСТИ УНИФИКАЦИИ:'), nl,
write(' • Унификация происходит один раз и необратима'), nl,
write(' • Переменная может унифицироваться только с одним значением'), nl,
write(' • В рекурсии каждый вызов создает новую область видимости'), nl,
write(' • Аккумуляторы передают состояние между вызовами'), nl.
% -----------------------------------------------
% Практические примеры
% -----------------------------------------------
demo_practical_examples :-
write('ПРАКТИЧЕСКИЕ ПРИМЕНЕНИЯ ПРЕДИКАТОВ:'), nl, nl,
write('СЦЕНАРИЙ 1: Криптографический анализ'), nl,
write('─────────────────────────────────────'), nl,
demo_crypto_analysis,
nl,
write('СЦЕНАРИЙ 2: Числовая теория'), nl,
write('───────────────────────────'), nl,
demo_number_theory,
nl,
write('СЦЕНАРИЙ 3: Анализ данных'), nl,
write('─────────────────────────'), nl,
demo_data_analysis,
nl.
demo_crypto_analysis :-
Numbers = [1234, 5678, 9876],
write('Анализ чисел для криптографических свойств:'), nl,
forall(member(N, Numbers), demo_crypto_number(N)).
demo_crypto_number(N) :-
digit_product_up(N, Product),
max_digit_not_div3_up(N, MaxDigit),
divisor_count_optimized(N, DivCount),
write('Число '), write(N), write(':'), nl,
write(' Произведение цифр: '), write(Product),
(Product =:= 0 -> write(' (содержит 0 - слабо)') ; write(' (без нулей - лучше)')), nl,
write(' Макс. цифра не дел. на 3: '), write(MaxDigit),
(MaxDigit =:= -1 -> write(' (все дел. на 3 - предсказуемо)') ; write(' (есть разнообразие)')), nl,
write(' Количество делителей: '), write(DivCount),
(DivCount =:= 2 -> write(' (простое - хорошо для криптографии)') ; write(' (составное)')), nl.
demo_number_theory :-
write('Исследование числовых свойств:'), nl,
% Поиск чисел с интересными свойствами
write('Поиск чисел от 1 до 100 с особыми свойствами:'), nl,
% Числа, где произведение цифр равно количеству делителей
findall(N, (between(1, 100, N),
digit_product_up(N, P),
divisor_count_optimized(N, D),
P =:= D), SpecialNumbers),
write('Числа, где произведение цифр = количеству делителей: '), write(SpecialNumbers), nl,
% Числа без цифр, делящихся на 3, но само число делится на 3
findall(N, (between(10, 100, N),
N mod 3 =:= 0,
max_digit_not_div3_up(N, M),
M =\= -1), ParadoxNumbers),
write('Числа дел. на 3, но есть цифры не дел. на 3: '), write(ParadoxNumbers), nl.
demo_data_analysis :-
write('Анализ последовательности чисел:'), nl,
Sequence = [123, 234, 345, 456, 567, 678, 789],
write('Последовательность: '), write(Sequence), nl,
% Анализ произведений цифр
findall(P, (member(N, Sequence), digit_product_up(N, P)), Products),
sum_list(Products, TotalProduct),
length(Products, Len),
AvgProduct is TotalProduct / Len,
write('Произведения цифр: '), write(Products), nl,
write('Среднее произведение: '), write(AvgProduct), nl,
% Анализ максимальных цифр
findall(M, (member(N, Sequence), max_digit_not_div3_up(N, M)), MaxDigits),
write('Макс. цифры не дел. на 3: '), write(MaxDigits), nl.
% -----------------------------------------------
% Производительность и оптимизация
% -----------------------------------------------
demo_performance_analysis :-
write('АНАЛИЗ ПРОИЗВОДИТЕЛЬНОСТИ И ОПТИМИЗАЦИИ:'), nl, nl,
write('1. СРАВНЕНИЕ АЛГОРИТМОВ ПОДСЧЕТА ДЕЛИТЕЛЕЙ:'), nl,
write(' Тестирование на различных размерах чисел'), nl, nl,
TestSizes = [100, 1000, 10000],
forall(member(Size, TestSizes), demo_divisor_scaling(Size)),
nl,
write('2. ВЛИЯНИЕ ДЛИНЫ ЧИСЛА НА ЦИФРОВЫЕ ОПЕРАЦИИ:'), nl,
LengthTests = [12, 1234, 123456, 12345678],
forall(member(N, LengthTests), demo_length_impact(N)),
nl,
write('3. ОПТИМИЗАЦИЯ И РЕКОМЕНДАЦИИ:'), nl,
write(' • Для подсчета делителей всегда используйте оптимизированную версию'), nl,
write(' • Рекурсия вниз предпочтительна для глубокой рекурсии'), nl,
write(' • Для цифровых операций длина числа влияет линейно'), nl,
write(' • Кэширование результатов может ускорить повторные вычисления'), nl.
demo_divisor_scaling(N) :-
get_time(T1),
divisor_count_down(N, C1),
get_time(T2),
divisor_count_optimized(N, C2),
get_time(T3),
TimeNormal is T2 - T1,
TimeOpt is T3 - T2,
SpeedUp is TimeNormal / TimeOpt,
write('N='), write(N), write(': обычный='), write(TimeNormal),
write('с, оптим.='), write(TimeOpt), write('с, ускорение='), write(SpeedUp), write('x'), nl.
demo_length_impact(N) :-
atom_chars(N, Chars),
length(Chars, Length),
get_time(T1),
digit_product_down(N, _),
get_time(T2),
max_digit_not_div3_down(N, _),
get_time(T3),
TimeProduct is T2 - T1,
TimeMaxDigit is T3 - T2,
write('Длина='), write(Length), write(', произведение='), write(TimeProduct),
write('с, макс.цифра='), write(TimeMaxDigit), write('с'), nl.
% -----------------------------------------------
% Интерактивные примеры
% -----------------------------------------------
demo_interactive_examples :-
write('=== ИНТЕРАКТИВНЫЕ ПРИМЕРЫ TASK2 ==='), nl,
write('Вы можете попробовать следующие запросы в интерактивной сессии:'), nl, nl,
write('1. Произведение цифр:'), nl,
write(' ?- digit_product_up(123, P). % P = 6'), nl,
write(' ?- digit_product_down(456, P). % P = 120'), nl,
write(' ?- digit_product_up(102, P). % P = 0 (содержит 0)'), nl, nl,
write('2. Максимальная цифра не делящаяся на 3:'), nl,
write(' ?- max_digit_not_div3_up(123, M). % M = 2'), nl,
write(' ?- max_digit_not_div3_down(369, M). % M = -1 (все дел. на 3)'), nl,
write(' ?- max_digit_not_div3_up(147, M). % M = 7'), nl, nl,
write('3. Количество делителей:'), nl,
write(' ?- divisor_count_up(12, C). % C = 6'), nl,
write(' ?- divisor_count_down(16, C). % C = 5'), nl,
write(' ?- divisor_count_optimized(100, C). % C = 9'), nl, nl,
write('4. Сравнение и анализ:'), nl,
write(' ?- compare_recursions(12345). % Сравнение всех методов'), nl,
write(' ?- benchmark_predicates(98765). % Измерение производительности'), nl,
write(' ?- interactive_demo. % Интерактивное меню'), nl, nl,
write('5. Проверка эквивалентности:'), nl,
write(' ?- digit_product_up(X, 24), digit_product_down(X, 24). % Поиск чисел'), nl,
write(' ?- max_digit_not_div3_up(X, 8), X > 0, X < 1000. % Числа с макс. цифрой 8'), nl, nl.