Eulerは完全数や友愛数を考えるにあたって、すべての約数の和を表す約数関数を定義し、駆使しました。(友愛数とは何かについては別の機会に紹介します。)
Maximaではは約数関数はdivsumという名前です。
ではグラフを書いてみましょう。
upper : 500$ ns : makelist(n, n, 1, upper)$ plot2d([[discrete, ns, map(divsum, ns)], 2*x], [x, 0, upper], [style, points, line])$
赤線上の点が完全数です。
約数関数は次のような性質を持ちます。
Maximaのdivsum関数は、引数が整数の時には値を計算してくれますが、引数が式の場合にはそのまま(名詞形)で、上記のような性質を利用した整理をしてくれません。
では、整理する関数を作ってみましょう。
matchdeclare(xx, all)$ defrule(dsrule0, divsum(xx, 1), dssimp(divsum(xx, 1)))$ matchdeclare(pp, lambda([x], integerp(x) and primep(x)))$ matchdeclare(nn, lambda([x], (integerp(x) or featurep(x, integer)) and x > 0))$ defrule(dsrule1, divsum(pp^nn, 1), (pp^(nn + 1) - 1)/(pp - 1))$ factorall(expr) := block([e], e : factor(expr), if atom(expr) then e else if inpart(e, 0) = "*" then map(factorall, e) else if inpart(e, 0) = "^" then factorall(inpart(e, 1))^inpart(e, 2) else e)$ base(factored) := if not atom(factored) and inpart(factored, 0) = "^" then inpart(factored, 1) else factored$ dssimp(expr) := block([arg], /* expr should be a form of "divsum(argument, 1)" by dsrule0. */ arg : factorall(inpart(expr, 1)), if inpart(arg, 0) = "*" then block([bases], bases : maplist(base, arg), if apply("and", maplist(integerp, bases)) then if (apply(ezgcd, bases))[1] = 1 then apply1(map(divsum, arg), dsrule1) else divsum(arg) else if readonly("Are ", bases, " relatively prime?[yes, no]: ") = 'yes then apply1(map(divsum, arg), dsrule1) else divsum(arg) ) else apply1(divsum(arg), dsrule1) )$ divsumsimp(expr) := applyb1(expr, dsrule0)$