Програмування у Sage

У цій частині підручника ми опишемо основні програмні засоби, необхідні для роботи із розділами математики поза елементарним рівнем. Перша глава, у якій описуємо об’єкти Sage, містить важливий матеріал, який треба засвоїти перед переходом до вивчення математичних структур. У другій главі розглядаються елементи програмування: умовні оператори, ітераційні цикли, а також створення власних команд та збереження сеансів. Для основних обчислень вона не є абсолютно необхідною, але цей матеріал конче знадобиться при виконанні будь-яких нетривіальних обчислень. У третій главі розглядається робота із деякими основними математичними пакетами, включеними у Sage. І наприкінці поміщено невелику главу про інтерактивну роботу у Sage.

Об’єкти Sage

Універсуми та приведення типів

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

У Sage цілим числам присвоюються імена ZZ, раціональним дійсним``RR``, і комплексним - CC.

sage: ZZ
Integer Ring
sage: QQ
Rational Field
sage: RR
Real Field with 53 bits of precision
sage: CC
Complex Field with 53 bits of precision

Перевіримо, чи деякий об’єкт перебуває в певному універсумі за допомогою оператора in.

sage: 1 in ZZ
True
sage: 1/2 in ZZ
False
sage: 1/2 in QQ
True
sage: sqrt(2) in QQ
False
sage: sqrt(2) in RR
True

Літерою I у Sage позначаємо квадратний корінь від -1 (можна також використати символ i):

sage: i^2
-1
sage: i^3
-I
sage: I in RR
False
sage: I in CC
True

Щоб вияснити, до якого універсуму належить деяке число, використаємо функцію parent(). У кожному випадку Sage вкаже на найпростішу генеральну множину об’єкта.

sage: parent(1)
Integer Ring
sage: parent(1/2)
Rational Field
sage: parent(5.7)
Real Field with 53 bits of precision
sage: parent(pi.n())
Real Field with 53 bits of precision

Іншим важливим універсумом є Кільце символів. Можна б подумати, що \sqrt{2} або \pi належать до всесвіту RR, тобто дійсних чисел, а I - до CC. Але RR та CC мають скінченну точність, а розглянуті числа задовольняють певним виразам, завдяки чому мають деякий спеціальний статус, наприклад, \sqrt{2}^2=2 та \sin(\pi)= 0. Кільце символів- це місце, у якому Sage зберігає такі числа з особливими властивостями. Також Кільце символів містить символічні змінні, див. “Змінні”.

sage: parent(sqrt(2))
Symbolic Ring
sage: parent(I)
Symbolic Ring
sage: parent(pi)
Symbolic Ring

Досить часто нам треба виконувати операції з елементами, які належать до різних універсумів, із виконанням деякого інтуїтивного приведення типу в загальному випадку над двома елементами, так, щоб вони містилися вже в одному універсумі. Наприклад, для обчислення виразу 1 + 1/2 = 3/2 перед початком будь-яких інших операцій виконується автоматичне приведення 1 до універсуму раціональних чисел. Це перетворення типу часто видається настільки природним, що ми навіть не усвідомлюємо його. Sage також робить велику частину таких інтуїтивних перетворень на льоту, так що ми не мусимо перейматися ними.

sage: parent(1 + 2)
Integer Ring
sage: parent(1/2 + 2)
Rational Field
sage: parent(1/2 + 2.0)
Real Field with 53 bits of precision

Sage також робить певні дії з символьними константами, такими як pi. Наприклад, ось що відбувається при змішуванні в одному виразі pi з десятковим числом.

sage: exp(1.)*pi
2.71828182845905*pi
sage: parent(exp(1.)*pi)
Symbolic Ring

Sage завжди вибиратиме універсум, у якому можна осягти максимальної точності. Такі ж дії будуть виконуватися для інших символьних констант, наприклад, e та i та для змінної поліному x.

sage: parent(2 + i)
Symbolic Ring
sage: parent(2 + x)
Symbolic Ring
sage: parent(2 + 2.0*x)
Symbolic Ring
sage: parent(2*pi + 2.0*e)
Symbolic Ring

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

sage: QQ(.5)
1/2
sage: parent(QQ(.5))
Rational Field
sage: RR(sqrt(2))
1.41421356237310
sage: parent(RR(sqrt(2)))
Real Field with 53 bits of precision

На щастя, у Sage є певні запобіжники, які не дають виконати деякі беззмістовні дії з перетворення типів; при цьому генерується повідомлення про помилку:exc:.TypeError.

sage: QQ(i)
ERROR: An unexpected error occurred while tokenizing input
The following traceback may be corrupted or invalid
The error message is: ('EOF in multi-line statement', (1170, 0))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
... * a lot of noise *
TypeError: Unable to coerce I to a rational

Вправи:

  1. До якого універсуму належить за замовчуванням x? У який універсум потрапить при оголошенні нова змінна y?

  2. Знайдіть універсальні множини (універсуми) для наступних виразів:

    1. 1 + 1/2
    2. 1 + 1/2.0
    3. 1/2 + i
    4. e + pi
    5. e.n() + pi
    6. e.n() + pi.()
  3. Для яких з наступних виразів операція приведення типу є змістовною?

    1. RR(1/2)
    2. QQ(1)
    3. ZZ(1/2)
    4. SR(1/2) (SR is the Symbolic Ring)
    5. CC(x)
  4. Якщо у Sage задати вираз x=1/2, у якому універсумі містиметься x?

Булеві змінні

Ще один важливий універсум - це булеві змінні. Універсум булевих змінних у Sage позначається як bool і містить тільки два елементи: True та False.

sage: parent(True)
<type 'bool'>

На булеві змінні діють кілька операторів (замість операторів виду +, *`над числами). Логічне *НІ* від булевої змінної дається оператором :obj:.not`.

sage: not True
False
sage: not False
True

Дві булеві змінні сполучаються за допомогою операторів and та or. Нехай X та Y - булеві змінні.

  • (X and Y) має значення True, якщо обидві змінні X,Y мають значення True. Якщо хоча б одна з них має значення False, цілий вираз теж є False.

  • (X or Y) є True, якщо хоча б одна з X та Y має значення True.

Понижче подано декілька прикладів

sage: True and False
False
sage: True and True
True
sage: True or False
True
sage: False or False
False

Для визначення порядку виконання обчислень у таких виразах можна використати дужки:

sage: (True or False) and False
False
sage: True or (False and False)
True

У першому прикладі спочатку обчислюється (True or False), що дає True, потім вираз True and False дає False. У другому прикладі обчислюється (False and False) (із результатом False), але далі True or False дає True.

Іншим важливим оператором на булевих змінних є оператор виключного АБО, який у Sage записується як ^^. (X ^^ Y) має значення True, якщо тільки одна зі змінних X або Y є True, а інша є False; у інших випадках значення буде False.

sage: True ^^ True         # xor (exclusive or) operator
False
sage: True ^^ False
True
sage: False ^^ False
False

Перевіримо, чи два об’єкти рівні між собою за допомогою оператору ==. Результат буде булевим:

sage: 1 == 1
True
sage: 1 == 0
False
sage: not(True or False) == True and False
True

Зауважте, що у запису є два знаки рівності підряд, а не один! Перевірити, чи є два об’єкти НЕрівними між собою, можна двома способами - операторами != та <>.

sage: 1 != 1
False
sage: 1 != 0
True
sage: 1 <> 0
True

Якщо два об’єкти належать до універсуму з впорядкуванням, тоді можна порівняти їх за допомогою оператору < із булевим результатом. Також можна використати оператор >= або аналогічно <= для дій порівняння менше/більше АБО рівний.

sage: 1 > 2
False
sage: 2 > 1
True
sage: 4.1 < 5.7
True
sage: 6 < 5
False
sage: 1 >= .99999
True
sage: 1 <= 35
True

Вправи:

  1. Перевірте, чи наступні вирази мають значення True, False, або є невизначеними:

    1. not (True or False) == (False and True)
    2. 1 >= 1
    3. 1 + i >= 2 - i
    4. ((3/2) > 1) or (2/3 < 1)
    5. ((3/2) > 1) ^^ (2/3 < 1)
    6. x > 1/2
  2. Яка породжувальна множина для x > 1/2? Чому Sage, як здається, працює з цим виразом за іншим алгоритмом, ніж з іншими у прикладах?

  3. Обчисліть за допомогою Sage, чи e є більшим за \pi? (Підказка: пригадайте, що ``e`` та ``pi`` за замовчуванням є символьними змінними.)

Змінні

Треба знати розділ “Декларування змінних

Термін ‘змінна’ може мати декілька значень. Так, у програмуванні під ‘змінною’ розуміють місце у пам’яті для збереження певної інформації та звертання до неї. У математиці змінна, наприклад, x - це величина з невизначеним значенням, символ, із яким можна виконувати такі ж арифметичні дії, як і з числами.

Sage зберігає обидва значення терміну. Ми будемо використовувати термін змінна для програмних змінних та символьна змінна для математичних змінних.

Sage виконує ініціалізацію Кільця символів для отримання однієї символьної змінної x. Вона підкоряється очікуваним правилам арифметичних дій.

sage: 3*x - x
2*x
sage: e*e^x
e^(x + 1)

Якщо потрібні інші символьні змінні, їх треба оголосити за допомогою команди var().

sage: e^x*e^y
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)

/Users/mosullivan/<ipython console> in <module>()

NameError: name 'y' is not defined
sage: var("y")
y
sage: e^x*e^y
e^(x + y)
sage:

Розглянемо змінні для збереження конкретного числа.

sage: m=2^19-1
sage: m
524287
sage: (m+1).factor()
2^19

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

У Sage можна перевизначити змінну із присвоєнням їй іншого значення:

sage: s=12
sage: s
12
sage: s=34
sage: s
34

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

sage: t=7
sage: t=t+1
sage: t
8

Також у Sage є зручний спосіб присвоєння значення кільком змінним одночасно.

sage: a,b=1,2
sage: a
1
sage: b
2

Крім того, можна виразити послідовність змінних за допомогою ком.

sage: c,d,e=2,3,5
sage: c,d,e
(2, 3, 5)

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

sage: a,_,c=1,2,3
sage: a
1
sage: c
3
sage: _,r = divmod(19,5)
sage: r
4

Швидкий спосіб ініціалізації двох змінних із одним і тим самим значенням - це зчеплення операцій присвоєння.

sage: a = b = 1
sage: a
1
sage: b
1

При визначенні змінної або символьної змінної вона зберігається у пам’яті до завершення сеансу. Іноді буває треба відновити вихідне значення змінної за замовчуванням. Це робиться за допомогою команди restore().

sage: x = 1
sage: a = 2
sage: restore('x')
sage: restore('a')
sage: x
x
sage: a
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/home/ayeq/sage/local/lib/python2.6/site-packages/sage/all_cmdline.pyc in <module>()
NameError: name 'a' is not defined

Можна скинути все оточення до значень за замовчуванням за допомогою команди reset().

sage: a = 1
sage: b = 2
sage: c = 5
sage: x = 56
sage: reset()
sage: a
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/home/ayeq/sage/local/lib/python2.6/site-packages/sage/all_cmdline.pyc in <module>()

NameError: name 'a' is not defined
sage: x
x

І на кінець, якщо треба насправді витерти змінну, можна використати команду del() для керування пам’яттю.

sage: a = [2, 3,4 ,5 ]
sage: del a
sage: a
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
/home/ayeq/sage/local/lib/python2.6/site-packages/sage/all_cmdline.pyc in <module>()

NameError: name 'a' is not defined

Вправи:

  1. Якщо у Sage ввести наступне:

    sage: a = 1
    sage: b = a
    sage: b = 2
    

    Яким буде значення a?

  2. Якщо у Sage ввести наступне:

    sage: f = x^2 + x + 1
    sage: f
    x^2 + x + 1
    sage: x = 3
    

    Яким буде значення f?

Списки

Списком називається впорядкована множина об’єктів. Елементи списку індексуються цілими числами від 0. Нижче ми наводимо простий приклад побудови списку та звернення до його елементів.

sage: [6,28,496,8128]
[6, 28, 496, 8128]
sage: L = [2,3,5,7,11,13,17,2]
sage: L[0]
2
sage: L[1]
3
sage: L[5]
13
sage: L[6]
17

Зверніть увагу на те, як було виконане звернення до елементів. Хоча 2 є перший елемент у списку L, але він викликається за індексом 0.

Команда len() повертає довжину списку.

sage: len(L)
8
sage: len([2,3,5,7,11])
5

Зауважте, що список довжини 5 має індекси від 0 до 4.

Списки можуть містити об’єкти з будь-якого універсуму, навіть “Рядки”.

sage: M = [ 'apple', 'pear']
sage: len(M)
2
parent(M[1])
<type 'str'>

Можна навіть задати список списків

sage: M = [[1,2],[1,3],[1,4]]
sage: M[2]
[1, 4]
sage: len(M)
3

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

sage: M[2][1]
4

Тут вираз M[2][1] треба сприймати як “Взяти елемент з індексом 1 у списку з індексом 2” у M. Зауважте, що директива M[2,1] не спрацює.

Зрізи та індексація

Одна з найбільш елегантних речей у python - це позначення у вигляді інтервалів, або зрізів. Нехай задано такий список:

sage: M = [1, 2, 0, 3, 4, 0, 4, 5]
sage: M
[1, 2, 0, 3, 4, 0, 4, 5]

і треба виділити з нього підсписок [0,3,4]. Із цією конвенцією позначень це можна зробити наступним чином:

sage: M[2:5]
[0, 3, 4]

Ми задаємо M[2:5], оскільки потрібний нам підсписок починається з елементу з індексом 2 і закінчується перед елементом з індексом 5.

Якщо залишити місце для останнього індексу порожнім, можна розтягнути зріз до кінця списку. Аналогічно, якщо випустити перший індекс, зріз почнеться від початку списку.

sage: M[2:]
[0, 3, 4, 0, 4, 5]
sage: M[:5]
[1, 2, 0, 3, 4]

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

sage: M[:]
[1, 2, 0, 3, 4, 0, 4, 5]

У зрізах можна використати і від’ємні індекси. При цьому позиція відлічується по відношенню до кінця (або початку) списку. Наприклад:

sage: M[:-2]
[1, 2, 0, 3, 4, 0]
sage: M[-2:]
[4,5]

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

sage: M[-4:-2]
[4, 0]
sage: M[-2:-2]
[]

Останній зріз порожній, оскільки початок списку співпадає з кінцем.

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

sage: M = [2,3,3,3,2,1,8,6,3]
sage: M.index(2)
0
sage: M.index(3)
1
sage: M.index(14)
...
ValueError: list.index(x): x not in list

Можна також порахувати, скільки разів елемент зустрічається у списку.

sage: M.count(3)
4

Створення

Sage пропонує зручний спосіб створення списків з послідовних цілих чисел, оскільки така задача зустрічається досить часто.

sage: [1..7]
[1, 2, 3, 4, 5, 6, 7]
sage: [4..9]
[4, 5, 6, 7, 8, 9]
sage: [2,4..10]
[2, 4, 6, 8, 10]

Перші два приклади досить наочні самі по собі; проте останній приклад зрозуміти дещо складніше. Якщо ввести [a,b..c] для цілих чисел a,b та c за умови a < b \leq c, ми дістанемо список [a,a+d,…,a+k*d], причому d=b-a та k є найбільшим цілим числом, таким, що a+kd \leq c. Якщо не дуже зрозуміло, наступні приклади трохи прояснять ситуацію.

sage: [1,4..13]
[1, 4, 7, 10, 13]
sage: [1,11..31]
[1, 11, 21, 31]
sage: [1,11..35]
[1, 11, 21, 31]

Крім того, цей метод побудови можна використати для деяких вбудованих символьних констант, типу pi.

sage: [pi,4*pi..32]
[pi, 4*pi, 7*pi, 10*pi]

Зміна списків

Сортування списку M можна виконати за допомогою методу sort().

sage: M = [2,3,3,3,2,1,8,6,3]
sage: M.sort(); y
[1, 2, 2, 3, 3, 3, 3, 6, 8]
sage: M.index(2)
1

Метод sort() змінює список на місці тим, що він змінює впорядкування елементів. Якщо треба зберегти список без змін, слід виконувати операцію сортування на копії списку, а не самому списку.

sage:  M = [2,3,3,3,2,1,8,6,3]
sage: M
[2, 3, 3, 3, 2, 1, 8, 6, 3]
sage: N = M[:]
sage: N.sort()
sage: N
[1, 2, 2, 3, 3, 3, 3, 6, 8]
sage: M
[2, 3, 3, 3, 2, 1, 8, 6, 3]

Змінити елементи у списку можна наступним чином:

sage: L = [1,2,3,4]
sage: L[0]=-1
sage: L
[-1, 2, 3, 4]

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

Для додавання елементу в кінець списку використовується метод append().

sage: L = [1,2,3]
sage: L.append(4)
sage: L
[1, 2, 3, 4]

Подібним чином можна використати метод extend() для зчеплення списків, тобто додавання списку в кінець іншого списку.

sage: L=[1,2]
sage: L.extend([10,11,12])
sage: L
[1, 2, 10, 11, 12]

Але, видається, для зчеплення списків простіше використати оператор +. Оскільки порядок, у якому слідують списки, має значення, вираз L + M взагалі не еквівалентний виразові M + L, якщо тільки ці два списки не містять ідентичний набір елементів.

sage: [1,3,5]+[2,4,6]+[100]
[1, 3, 5, 2, 4, 6, 100]
sage: [2,4,6]+[1,3,5]+[100]
[2, 4, 6, 1, 3, 5, 100]

Якщо треба видалити елемент зі списку, використаємо метод meth:.remove.

sage: L = [3,5,11,13,17,19,29,31]
sage: L.remove(11)
sage: L
[3, 5, 13, 17, 19, 29, 31]

Відмітимо, що список може містити один і той сам елемент кілька разів; метод remove() усуває тільки перший екземпляр даного елементу.

sage: M = [1,2,3,0,3,4,4,0,4,5]
sage: M.remove(3)
sage: M
[1, 2, 0, 3, 4, 4, 0, 4, 5]
sage: M.remove(4)
sage: M
[1, 2, 0, 3, 4, 0, 4, 5]

Операції зі списками

Команди sum() та prod() можуть приймати список як аргумент у тих випадках, коли такі операції для списку є змістовними.

sum() повертає суму аргументів:

sage: sum([1,2,3])
6
sage: sum([1..100])
5050

а prod() - добуток.

sage: prod([1..4])
24

Сума та добуток визначаються на списках, у яких арифметичні операції мають зміст. У іншому випадку буде повідомлення про досить серйозну помилку.

sage: sum( [1,2,3,"cat",])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last
... (Lengthy error message)
TypeError: unsupported operand parent(s) for '+': 'Integer Ring' and '<type 'str'>'

Об’єднання (конкатенація) - це не єдиний спосіб поєднати разом елементи двох списків. Інший корисний інструмент - команда zip(), яка об’єднує елементи двох списків попарно по порядку.

sage: zip([1,2,3,4],['a','b','c','d'] )
[(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]

Якщо довжини списків неоднакові, :func:`.zip`об’єднує елементи доти, поки не скінчиться коротший зі списків, решту ігнорує.

sage: zip([1,2,3,4],['a','b','c']   )
[(1, 'a'), (2, 'b'), (3, 'c')]
sage: zip([1],['a','b','c']   )
[(1, 'a')]

Інша корисна команда для роботи зі списками - map(). Вона має два аргументи: функцію f та список [a0,…,an-1], а повертає результат застосування функції до кожного елементу списку, [f(a0),…,f(an-1)]

sage: map( cos, [0, pi/4, pi/2, 3*pi/4, pi] )
[1, 1/2*sqrt(2), 0, -1/2*sqrt(2), -1]
sage: map(factorial,[1,2,3,4,5])
[1, 2, 6, 24, 120]
sage: sum(map(exp,[1,2,3,4,5]))
e + e^2 + e^3 + e^4 + e^5

Команду map() часто використовують у функціональному програмуванні. Більше про цей стиль програмування для мови python можна дізнатись з документації для python.

Вправи:

  1. Розглянемо списки L = [1, -2, 10, 13] та M = [4, 3, 5, -7]. Додайте L в кінець M. Зробіть те ж саме, але з M.

  2. Розглянемо список L = [1, 3, 4, [1,5,6], 8, -9]. Який індекс має елемент [1,5,6]? Видаліть цей елемент з L.

  3. Нехай L = [3,4,18,17,2,'a'] та M = [ 14, 23, 'b',   'c']. Зробіт= наступні дії у Sage:

    1. Під’єднайте елементи списку M в кінець L без зміни L.

    2. Те ж саме зробіть, але змініть L на місці.

    3. Вставте M як елемент у кінець L, при цьому виконайте зміну L на місці.

    4. Видаліть щойно вставлений список M.

    5. Поясніть різницю між методами extend() та append().

  4. Нехай L = [1,2,5, 14, 17, 20]. Які підсписки викликаються за допомогою наступних зрізів?

    1. L[:-1]
    2. L[-1:]
    3. L[3:]
    4. L[0:3]
    5. L[-4:-1]
  5. Використаємо таке ж саме L, як у попередній задачі. Побудуйте зріз, який дозволяє витягти з L наступні підсписки: (Знайдіть декілька способів розв’язання)

    1. [5,14,17].
    2. [1,2,5].
    3. [1]
    4. [20]
  6. Нехай L = ['a', 9, 10, 17, 'a', 'b', 10]. Усуньте з L всі літери.

Множини

Множина (або Set у Sage) - це тип даних, який має багато спільних рис із математичними множинами, але відрізняється від списку у декількох провідних рисах:

  • Елементи множини не впорядковані, отже, до них не можна звернутись за індексом.

  • Елемент у множині може з’явитись тільки один раз.

Щоб проілюструвати цю останню властивість, побудуємо множину конвертуванням списку до типу множин.

sage: y = [2,3,3,3,2,1,8,6,3]
sage: A = Set(y)
sage: A
{8, 1, 2, 3, 6}

Для визначення розміру множини використовуємо метод cardinality().

sage: A.cardinality()
5

За допомогою оператора in можна перевірити приналежність елементу до множини.

sage: 8 in A
True
sage: 10 in A
False

Із цими об’єктами можна використовувати поточні операції із множинами - union(), intersection(), difference() and symmetric_difference(). Наприклад:

sage: B = Set([8,6,17,-4,20, -2 ])
sage: B
{17, 20, 6, 8, -4, -2}
sage: A.union(B)
{1, 2, 3, 6, 8, 17, 20, -4, -2}
sage: A.intersection(B)
{8, 6}
sage: A.difference(B)
{1, 2, 3}
sage: B.difference(A)
{17, 20, -4, -2}
sage: A.symmetric_difference(B)
{17, 2, 3, 20, 1, -4, -2}

Підмножини, а також підмножини із заданою кількістю елементів будуються за допомогою методу subsets(). Відмітимо, що метод subsets() генерує список підмножин.

sage: A = Set([1,2,3]); A
{1, 2, 3}
sage: powA = A.subsets(); powA
Subsets of {1, 2, 3}
sage: pairsA = A.subsets(2); pairsA
Subsets of {1, 2, 3} of size 2
sage: powA.list()
[{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
sage: pairsA.list()
[{1, 2}, {1, 3}, {2, 3}]

Вправи:

  1. Розглянемо множини A = \left\{1, -4, 2 \right\} та B = \left\{ 3, 2, 1 \right\}. Виконайте у Sage наступні операції над множинами:

    1. A \cup B
    2. A \cap B
    3. A \setminus B
    4. B \setminus A
    5. \left(A \setminus B \right) \cup \left(B \setminus A \right)

Дивись також

Підручник Sage: Множини

Рядки

Для побудови рядка у Sage можна використати лапки - прості або подвійні:

sage: s='I am a string'
sage: s
'I am a string'
sage: print s
I am a string

Зауважте, яка різниця між запитом значення a та видачею команди для Sage на вивід print a. Як і у випадку списків, елементи рядку можна викликати за їхніми індексами.

sage: a='mathematics'
sage: a[0]
'm'
sage: a[4]
'e'

Довжину рядку видає команда len().

sage: b='Gauss'
sage: len(b)
5

Як і у списках, можна проводити операцію об’єднання (конкатенації) рядків шляхом їх додавання.

sage: b + " is " + a
'Gauss is mathematics'

а за допомогою методу split() рядок можна розділити.

sage: s.split()
['I', 'am', 'a', 'string']

Ця операція розділяє рядок на список слів. Можна розділити список за іншими символами у якості роздільників. Наприклад, список можна отримати з наступних значень, відділених комами.:

sage: vals = "18,spam,eggs,28,70,287,cats"
sage: vals.split(',')
['18', 'spam', 'eggs', '28', '70', '287', 'cats']

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

sage: map(Integer, data.split(','))
[17, 18, 20, 19, 18, 20]

Зауважте різницю виводу із результатом використання тільки методу split().

sage: data.split(',')
['17', '18', '20', '19', '18', '20']

Список, наведений вище, містить об’єкти рядки, у яких є числа. Треба конвертувати ці рядки у типи, який ми будемо використовувати.

Операція, протилежна розбиттю рядка - це об’єднання елементів списку. Це робиться за допомогою команди join().

sage: L = ['Learning', 'Sage', 'is', 'easy.']
sage: join(L)
'Learning Sage is easy.'

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

sage: join(L,',')
'Learning,Sage,is,easy.'

Вправи:

  1. Візьмемо рядок s = 'This is a string!. Що дадуть наступні команди?

    1. s[:-1] + ‘.’
    2. s[0:7] + ” not ” + s[8:]
  2. Тепер розглянемо рядок s = 'This is a sentence. This is another sentence.'. Розбийте s на список з двох речень.

  3. Тепер візьмемо список рядків L = ['This is', 'a', 'string']. Об’єднайте елементи списку і згенеруйте рядок ‘This is a string’`.

  4. Команди map() та Integer() можна використати для перетворення рядка цілих у цілі, із якими працює Sage.

Засоби програмування

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

Умовні оператори

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

sage: n=44
sage: if n%2 == 0:
....:     print n/2
....:
22
sage: n=37
sage: if n%2 == 0:
....:     print n/2
....:
sage:

Оскільки n=44 парне, умова задовольняється, і виконується команда print(); навпаки, із n=37 нічого не відбувається, бо умова не виконана. Майже вся робота з програмування - це вміле застосування низки подібних простих тверджень.

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

Бувають ситуації, коли треба перевірити, що вираз задовольняє більш ніж одній умові. Для цього використовується твердження elif - скорочена форма запису фрази else if.

sage: m=31
sage: if m%3==0:
....:     print m/3
....: elif m%3==1:
....:     print (m-1)/3
....:
10

Зауважте, що для elif ми повертаємось на той самий рівень відступу, як і для if. Можна використати довільну кількість операторів elif. Умови перевіряються одна за однією, і весь блок виконується, коли задовольняється якась одна перша. При цьому подальші умови вже не перевіряються. Розглянемо простий приклад:

sage: r=55
sage: if 11.divides(r):
....:     print 11
....: elif r==55:
....:     print 55
....:
11

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

У попередньому прикладі було також використано скорочений запис. Вираз``11.divides(r)`` сам по собі повертає значення True або False, тому не було необхідності писати тут вираз з оператором рівності. Можна було б використати повний синтаксис 11.divides(r)==True, але це у даному випадку зайве.

Іноді треба закласти в алгоритм виконання певних дій, якщо жодна з умов не справджується. Для цього використуємо оператор else.

sage: n=2*3*5+1
sage: if 2.divides(n):
....:     print 2
....: elif 3.divides(n):

....:     print 3
....: else:
....:     print n
....:
31

Оскільки не виконано жодної з умов, код переходить на гілку за замовчуванням та друкує число 31.

Цикли з умовою

Треба знати розділи Змінні та Булеві змінні

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

sage: i=0
sage: while i < 5:
....:     print i^2
....:     i=i+1
....:
0
1
4
9
16

Коли умова i<5 приймає значення False, Sage виходить з циклу; змінна i все ще залишається у пам’яті.

Цикли For

Треба знати розділи Змінні, Булеві змінні та Списки

Цикл з лічильником (цикл FOR) послідовно виконує блок коду деяку фіксовану кількість разів. У Sage цикли з лічильником виконують ітерацію за фіксованим списком.

sage: for i in [0..4]:
....:     print i^2
....:
0
1
4
9
16

Можна проводити ітерацію за будь-яким списком, необов’язково за послідовними цілими. Наведемо кілька екзотичних прикладів.

sage: for str in ["apple","banana","coconut","dates"]:
....:     print str.capitalize()
....:
Apple
Banana
Coconut
Dates
sage: for char in "Leonhard Euler":
....:     print char.swapcase()
....:
l
E
O
N
H
A
R
D

e
U
L
E
R

Згортання списків (цикли у списках)

Треба знати розділи Списки та Цикли For

A particularly useful technique in python (and Sage by extension) is the construction of lists using list comprehensions. This feature is very similar to the set builder notation we often use in mathematics. For example, the set of even integers can be written as:

\left\{ 2\cdot k\ \vert\ k \in \mathbb{Z} \right\}

У цьому випадку ми не перераховуємо елементи множини, але даємо правила побудови множини. На мові Python можна зробити дуже подібну операцію із розміщенням for усередині списку, як у наступному прикладі. Тут показано, як збудувати список парних цілих чисел від 0 до 20.

sage: [ 2*k for k in [0..10] ]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

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

Згортання списків можна використати, щоб подіяти певною функцією на кожний елемент даного списку, подібно до того, як це ми робили командою map().

sage: [pi/4,pi/2..2*pi]
[1/4*pi, 1/2*pi, 3/4*pi, pi, 5/4*pi, 3/2*pi, 7/4*pi, 2*pi]
sage: [ cos(x) for x in [pi/4, pi/2..2*pi]]
[1/2*sqrt(2), 0, -1/2*sqrt(2), -1, -1/2*sqrt(2), 0, 1/2*sqrt(2), 1]

Також у операції згортання списків можна використовувати фільтри (або обмеження) шляхом додавання умови до згортання списку. Наприклад, для побудови списку з натуральних чисел, менших за 20, що одночасно є взаємно простими із 20 виконаємо наступне:

sage: [ k for k in [1..19] if gcd(k,20) == 1 ]
[1, 3, 7, 9, 11, 13, 17, 19]

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

\left\{ k \in \mathbb{N}\ \vert\ k < 20 \ \textrm{and}\ \gcd(k,20) = 1 \right\}

У математиці часто використовується декартів добуток двох множин:

A \times B = \left\{ \left(a, b \right)\ | \ a \in A, b \in B \right\}

Подібну дію можна виконати за допомогою низки операторів for у згортанні списку. Наприклад, щоб побудувати список пар елементів з раніше побудованого списку виконаємо наступну команду:

sage: U =  [ k for k in [1..19] if gcd(k,20) == 1]
sage: [ (a,b) for a in U for b in U ]
[(1, 1), (1, 3), (1, 7), (1, 9), (1, 11), (1, 13), (1, 17), (1, 19), (3, 1), (3, 3), (3, 7), (3, 9), (3, 11), (3, 13), (3, 17), (3, 19), (7, 1), (7, 3), (7, 7), (7, 9), (7, 11), (7, 13), (7, 17), (7, 19), (9, 1), (9, 3), (9, 7), (9, 9), (9, 11), (9, 13), (9, 17), (9, 19), (11, 1), (11, 3), (11, 7), (11, 9), (11, 11), (11, 13), (11, 17), (11, 19), (13, 1), (13, 3), (13, 7), (13, 9), (13, 11), (13, 13), (13, 17), (13, 19), (17, 1), (17, 3), (17, 7), (17, 9), (17, 11), (17, 13), (17, 17), (17, 19), (19, 1), (19, 3), (19, 7), (19, 9), (19, 11), (19, 13), (19, 17), (19, 19)]

It should be noted that I didn’t only have to form tuples of the pairs of elements. I can also find the product or the sum of them. Any valid expression involving a and b will be fine.

sage: [ a*b for a in U for b in U ]
[1, 3, 7, 9, 11, 13, 17, 19, 3, 9, 21, 27, 33, 39, 51, 57, 7, 21, 49, 63, 77, 91, 119, 133, 9, 27, 63, 81, 99, 117, 153, 171, 11, 33, 77, 99, 121, 143, 187, 209, 13, 39, 91, 117, 143, 169, 221, 247, 17, 51, 119, 153, 187, 221, 289, 323, 19, 57, 133, 171, 209, 247, 323, 361]
sage: [ a + b for a in U for b in U ]
[2, 4, 8, 10, 12, 14, 18, 20, 4, 6, 10, 12, 14, 16, 20, 22, 8, 10, 14, 16, 18, 20, 24, 26, 10, 12, 16, 18, 20, 22, 26, 28, 12, 14, 18, 20, 22, 24, 28, 30, 14, 16, 20, 22, 24, 26, 30, 32, 18, 20, 24, 26, 28, 30, 34, 36, 20, 22, 26, 28, 30, 32, 36, 38]
sage: [ gcd(a,b) for a in U for b in U ]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 7, 1, 1, 1, 1, 1, 1, 3, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, 1, 1, 1, 1, 1, 1, 19]

Подібні побудови працюють для більш ніж 2 множин; для цього треба додати більше виразів for.

Оскільки згортання списків допускає усередині будь-які коректні вирази, можна додати ще один умовний оператор, який впливає на виведення списку. Наприклад, візьмемо список цілих, взаємно простих з 20 та перевіримо, чи є вони самі простими числами.

sage: U
[1, 3, 7, 9, 11, 13, 17, 19]
sage: [ 'prime' if x.is_prime() else 'not prime' for x in U]
['not prime', 'prime', 'prime', 'not prime', 'prime', 'prime', 'prime', 'prime']

Вправи:

  1. Використаємо згортання списків для генерації списків, що містять такі ж об’єкти, як наступні множини:

    1. Множина всіх непарних цілих, більших -10 та менших 30.

    2. Множина всіх цілих чисел, що діляться на 3, менші або рівні 100 та більші за -20.

    3. Множина всіх простих чисел, менших за 100.

  2. За допомогою операції згортання списку порахуйте \tan(x) для всіх x \in \left\{ 0, \pi/4, \pi/2, 3\pi/4, \pi \right\}

Визначення власних команд

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

Наприклад, нам треба порахувати найбільший спільний дільник 75 та 21. Для цього можна використати алгоритм Евкліда у Sage. Це виглядає наступним чином:

sage: def euclid(a,b):
....:     r = a%b
....:     while r != 0:
....:         a=b; b=r
....:         r = a%b
....:     return b

a та b називаються аргументами команди, а вираз після ключового слова return називається повертальне значення. Аргументи є вводом команди, а повертальне значення - виводом.

Для тих з читачів, хто вже мав справу з програмуванням: ви можете помітити, що у нас відсутні віддільники блоків, тобто знаки на кшталт ;, або end. Sage, як і Python, для виділення початку та кінця блоку використовує відступи. Такий синтаксис змушує програміста до написання більш наочного коду шляхом візуального відділення блоків коду одного від іншого.

Після визначення команди euclid код можна повторно використати із іншими аргументами, так, як і будь-яку вбудовану команду.

sage: euclid(75,21)
3
sage: euclid(455,67)
1
sage: euclid(754,99)
1
sage: euclid(756,9)
9

Команди користувача можуть мати будь-яку кількість аргументів, і навіть не мати жодного.

sage: def g(x,y):
....:     return x*y
....:
sage: g(2,3)
6
sage: g(sqrt(2),sqrt(2))
2
sage: def h():
....:     return 1/2
....:
sage: h()
1/2

Defining a return value is also optional, but all commands in Sage return something. If we do not specify a return value, then Sage returns the empty object None.

sage: def lazy(x):
....:     print x^2
....:
sage: lazy(sqrt(3))
3
sage: a =  lazy(sqrt(3))
3
sage: a
None

What the above is showing is that while the command displays the number 3, the return value is actually None. While this is valid code, it is good practice to have your commands actually return the value that you are interested in computing.

By separating the values with commas, your command can have multiple return values.

sage: def s(x):
....:     return x^2,x^3
....:
sage: s(1)
(1, 1)
sage: s(2)
(4, 8)
sage: a,b=s(3)
sage: a
9
sage: b
27

Defining your own commands in SAGE is easy. However, elegantly encapsulating your code is an art which requires a lot of practice and thought. For a more thorough introduction to functions (commands), the following chapter on Python functions is a good place to start.

External Files and Sessions

In practice, especially when using sage for research and projects, it is convenient to load external files into Sage. One such instance is when we have a block of code which we wish to run for several different cases. It would be quite tedious to retype all of the code; instead we read it from an external file.

Suppose we have a file in the same directory from which we started Sage called pythag.sage with the following content.

# Begin pythag.sage
a=3
b=4
c=sqrt(a^2+b^2)
print c
# End

Note that all characters after a # of a Sage file are ignored when loaded. We may now load the file in Sage using the load() command.

sage: load pythag.sage
5

After having loaded the file, all of the variables initialized now exist in our Sage session.

sage: a,b,c
(3, 4, 5)

Sage allows us to save a session to pick up where we left off. That is, suppose we have done various calculations and have several variables stored. We may call the save_session function to store our session into a file in our working directly (typically sage_session.sobj). Following, we may exit Sage, power off our computer, or what have you. At any later time, we may load the file by opening Sage from the directory containing the save file and using the load_session function.

Here is an example:

sage: a=101
sage: b=103
sage: save_session()
sage: exit
Exiting SAGE (CPU time 0m0.06s, Wall time 0m31.27s).

Now start Sage from the same folder as the save file.

sage: load_session()
sage: a
101
sage: b
103

We may specify the name of a save session, if we so desire.

sage: T=1729
sage: save_session('ramanujan')
sage: exit
Exiting SAGE (CPU time 0m0.06s, Wall time 0m16.57s).

And again we load our session ramanujan with load_session().

sage: load_session('ramanujan')
sage: T
1729

Packages within Sage

There are many open-source software packages available for doing specialized mathematics. One of the objectives of Sage developers is to create a single clean interface from which these packages may all be accessed. For many computations in advanced mathematics Sage uses the functionality in one of these packages. A Sage use user can also explicitly call a function from one of the packages. This chapter briefly describes how to do so.

GAP

For this portion of the tutorial we are going to show how to use GAP from within a Sage session. The commands here follow closely with the Groups and Homomorphisms section of the GAP tutorial. A reader who is interested in learning more about the capabilities of this system shoud consult the Gap Project’s main website.

You can pass a command to GAP by using gap() with the command as a string. The following example constructs the symmetric group on eight points using GAP.

sage: s8 = gap('Group( (1,2), (1,2,3,4,5,6,7,8) )')
sage: s8
Group( [ (1,2), (1,2,3,4,5,6,7,8) ] )

s8 has GAP as a parent.

sage: parent(s8)
Gap

The interface to the GAP system translates the commands in GAP to methods in Sage. For example, to compute the Derived Subgroup of S_8 you use the DerivedSubgroup() method.

sage: a8 = s8.DerivedSubgroup(); a8
Group( [ (1,2,3), (2,3,4), (2,4)(3,5), (2,6,4), (2,4)(5,7), (2,8,6,4)(3,5) ] )
sage: a8.Size(); a8.IsAbelian(); a8.IsPerfect()
20160
false
true

The output of s8.DerivedSubgroup() is identical to the output of the GAP command DerivedSubgroup(s8) and this is the common convention when the command has one argument. When it requires two, say the group and an additional parameter, the additional parameter is given as an argument to the method. For example, the GAP command SylowSubgroup(a8,2) computes the maximal 2-subgroup of A_8. The following Sage code does the same, then uses GAP to compute it’s size.

sage: sy12 = a8.SylowSubgroup(2); sy12.Size()
64

In the same vein, we can use GAP to compute the normalizer’s and centralizers of these groups.

sage: a8.Normalizer(sy12)
Group( [ (1,6)(2,4), (1,6)(5,8), (2,4)(3,7), (2,8)(4,5), (1,7)(2,8)(3,6)(4,5),
  (1,8)(2,7)(3,4)(5,6) ] )
sage: a8.Normalizer(sy12) == sy12
True
sage: cent = a8.Centralizer(sy12.Centre());
sage: cent
Group( [ ( 1, 6)( 2, 4)( 3, 7)( 5, 8), (3,5)(7,8), (3,7)(5,8), (2,3)(4,7),
  (1,2)(4,6) ] )
sage: cent.Size()
192

Gap сам містить команди для операцій над списками об’єктів. У цьому прикладі ми спочатку обрахуємо виведений ряд cent, а потім порахуємо розмір кожної з цих підгруп за допомогою команди GAP List().

sage: cent.DerivedSeries(); cent.DerivedSeries().List('Size')
[ Group( [ ( 1, 6)( 2, 4)( 3, 7)( 5, 8), (3,5)(7,8), (3,7)(5,8), (2,3)(4,7),
      (1,2)(4,6) ] ),
  Group( [ (2,4)(3,7), ( 1, 3)( 2, 8)( 4, 5)( 6, 7), ( 1, 7, 4)( 2, 6, 3) ] ),
  Group( [ ( 1, 6)( 2, 4)( 3, 7)( 5, 8), ( 1, 6)( 3, 7),
      ( 1, 4)( 2, 6)( 3, 5)( 7, 8), ( 1, 7)( 2, 5)( 3, 6)( 4, 8),
      ( 1, 4, 6, 2)( 3, 8, 7, 5) ] ),
  Group( [ ( 1, 6)( 2, 4)( 3, 7)( 5, 8) ] ), Group( () ) ]
[ 192, 96, 32, 2, 1 ]

Оскільки команда GAP будує повноправний об’єкт Sage, можна виконати такі ж дії, але способом, більш притаманним Sage, за допомогою згортання списків.

sage: [ g.Size() for g in cent.DerivedSeries() ]
[192, 96, 32, 2, 1]

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

sage: gens = s8.GeneratorsOfGroup(); gens
[ (1,2), (1,2,3,4,5,6,7,8) ]
sage: SG = PermutationGroup(gens); SG
Permutation Group with generators [(1,2), (1,2,3,4,5,6,7,8)]
sage: parent(SG)
<class 'sage.groups.perm_gps.permgroup.PermutationGroup_generic_with_category'>

Перехід від групи Sage до GAP виконується ще простіше.

sage: gap(SG)
Group( [ (1,2), (1,2,3,4,5,6,7,8) ] )
sage: parent(gap(SG))
Gap

Іноді постає необхідність використати GAP безпосередньо, без інтерфейсу. У командному рядку команда gap_console() виконує саме це.

sage: gap_console()
GAP4, Version: 4.4.12 of 17-Dec-2008, x86_64-unknown-linux-gnu-gcc
gap>

З цього режиму можна вийти введенням quit; у рядку GAP.

gap> quit;
sage:

При роботі з блокнотом безпосереднє використання GAP є ще простішим - ми просто вибираємо GAP з розгортального меню.

Using GAP directly from the Sage Notebook

Тепер блокнот Sage виконує функцію веб-інтерфейса до системи GAP.

Singular

Подібно до інтерфейсу GAP, інтерфейс, що надає Sage для Singular, заміняє команди мови певними методами у Sage. Наприклад, наступний код у Singular:

> ring R = 0,(x,y,z),lp;
> R;
//   characteristic : 0
//   number of vars : 3
//        block   1 : ordering lp
//                  : names    x y z
//        block   2 : ordering C

Він будує поліномінальне кільце на трьох змінних x, y та z над полем характеристики 0 із використанням лексикографічного впорядкування елементів. Для такої ж дії у Sage використовується метод ring() об’єкту singular.

sage: R = singular.ring('0','(x,y,z)','lp')
sage: R
//   characteristic : 0
//   number of vars : 3
//        block   1 : ordering lp
//                  : names    x y z
//        block   2 : ordering C

Оскільки переважна частина синтаксису Singular для Sage не є змістовною, важливо звертати увагу на лапки довкола аргументів.

Поліноми будуються у цьому кільці за допомогою методу poly().

sage: p = singular.poly('x^2 * y^2 - 1')
sage: q = singular.poly('x^2 * y^2 - z')
sage: singular.ideal([p,q])
x^2*y^2-1,
x^2*y^2-z

Щоб побудувати ідеал (на R), згенерований цими поліномами та базис Гребнера, слід ввести наступне.

sage: I = singular.ideal([p,q])
sage: I.groebner()
z-1,
x^2*y^2-z

Зведення за модулем у цьому ідеалі виконується за допомогою методу reduce().

sage: r = singular.poly('x^3 - x^2 * y^2 - x^2 * z  + x')
sage: singular.reduce(p,I)
z-1
sage: singular.reduce(q,I)
0
sage: singular.reduce(r,I)
x^3-x^2*z+x-z

а якщо треба провести таке зведення із базисом Гребнера, використовується комбінація описаних вище методів.

sage: singular.reduce(q,I.groebner())
0
sage: singular.reduce(p,I.groebner())
0
sage: singular.reduce(r,I.groebner())
x^3-x^2+x-1

Лапки при передачі об’єкту Singular непотрібні, як і видно з кількох останніх прикладів, оскільки неоднозначності не виникає.

Finally a task that Singular excels at is the factorization of multivariate polynomials. This is done using the factorize() method.

sage: p.factorize()
[1]:
   _[1]=1
   _[2]=x*y-1
   _[3]=x*y+1
[2]:
   1,1,1
sage: q.factorize()
[1]:
   _[1]=1
   _[2]=x^2*y^2-z
[2]:
   1,1
sage: r.factorize()
[1]:
   _[1]=-1
   _[2]=x
   _[3]=-x^2+x*y^2+x*z-1
[2]:
   1,1,1

Дивись також

http://www.singular.uni-kl.de

Використання пакетів Python у Sage

Interactive Demonstrations in the Notebook

In this section we will discuss the creation of interactive “applets” in the Sage notebook. These are done using the @interact decorator and are often called interacts. A decorator is a just a fancy piece of python which allows for you to create new functions out of old in a quick and concise fashion. You don’t have to fully understand decorators to be able to follow this material but If you are interested you can read a very nice blog post about decorators by Bruce Eckel of Thinking in Python Fame.

Почнемо з найпростішого аплету. Він створює одне вікно вводу і потім виводить результат.

Simple "Hello World" Interact Applet

Відмітьте, як зміна тексту у вікні вводу викликає зміну виводу. Щоразу, як щось змінюється в інтерактивній частині, відбувається оновлення “аплету” із віддзеркаленням цих змін. Це - основа інтерактивного підходу.

Simple "Hello World" Interact Applet

Next we will add another control to the applet. This time we will add a slider. This control has a handle which the user can slide horizontally, and by sliding change a number in pre-defined increments. For this example, the slider has 0 as it’s smallest number and 10 as it’s largest and moves in increments of 1 unit.

Simple "Hello World" Interact Applet

Next we will add a selection control. This control allows the user to select one of a finite number of different options. In this case, the user can select any color, as long as that color is red, blue, green, or black.

Simple "Hello World" Interact Applet

While this initial example shows the use of a couple of common interactive controls, it still does not do anything very interesting. The next example will combine both the use of sliding and selection controls toward creating an applet which plots the trigonometric functions and there standard transformations.

Example of Trigonometric Plotter Interact.

The example here only scratches the surface of what is possible with Sage interacts. For a, growing, list of examples of interacts see this page on the sage wiki.