(*Minimal redundant expansions in Gaussian Integers*) BeginPackage["MinimalRedundantGauss`"] CNS::usage="CNS[d_0, ..., d_l] represents a digit expansion with \ respect to some basis." ExpandCNS::usage ="ExpandCNS[beta][d_0,...,d_l] gives Sum[d_j beta^j, \ {j,0,l}]." StandardCNS::usage="StandardCNS[alpha, beta] gives the standard \ expansion of alpha in the canonical number system defined by beta." MinimumCNS::usage="MinimumCNS[alpha,beta] gives all minimal expansions \ of alpha in base beta with respect to the costs (4). Previous results \ are stored in order to improve running time. This may consume much memory." ShortestCNS::usage="ShortestCNS[alpha,beta] gives a shortest expansion \ of alpha in base beta using digits of absolute value < Norm[beta]. Previous results \ are stored in order to improve running time. This may consume much memory." FindRule::usage="FindRule[CNS[d_0,...,d_l],beta] finds the set of r_0 \ such that the conditions of Lemma 4 are fulfilled." Begin["`Private`"] (*Utilities for complex numbers*) norm[z_Complex] := Re[z]^2 + Im[z]^2 modbase[z_?NumberQ, beta_?NumberQ] := With[{c = Re[z], d = Im[z], a = -Re[beta]}, Mod[c + a*d, norm[beta]]] (*Utilities*) ExpandCNS[beta_?NumberQ][u__] := Module[{i, l = {u}}, Sum[l[[i + 1]]*beta^i, {i, 0, Length[l] - 1}]] cost[CNS[u___]] := Module[{l = {u}}, Plus @@ Map[Abs, l] ] (*Bounds for the Digits *) possibleDigits[r_Integer, beta_?NumberQ] := Module[{n = -Re[beta], digitbound, i}, digitbound = Which[n >= 3, n^2, n == 2, 8, n == 1, 2]; Select[Table[i, {i, -digitbound, +digitbound}], Mod[#, n^2 + 1] == Mod[r, n^2 + 1] &] ] (*Symbolic Manipulation of CNS*) CNS /: Dot[u_CNS, v_CNS] := Join[u, v] CNS /: Power[u_CNS, 0] := CNS[] CNS /: Power[u_CNS, 1] := u CNS /: Power[u_CNS, n_Integer /; n > 1] := u^Floor[n/2].u^Floor[n/2].u^Mod[n, 2] (*Expansion in the standard Canonical Number System*) StandardCNS[0, beta_Complex] = CNS[]; StandardCNS[z_?NumberQ, beta_?NumberQ] := Module[{r, z1}, r = modbase[z, beta]; z1 = (z - r)/beta; Prepend[StandardCNS[z1, beta], r] ] (* Minimal Expansion *) MinimumCNS[0, ___] = {CNS[]}; MinimumCNS[z_?NumberQ, beta_?NumberQ, first_?IntegerQ, maxweight_?IntegerQ] := Module[{expansions}, expansions = MinimumCNS[(z - first)/beta, beta, maxweight - Abs[first]]; expansions = Map[Prepend[#, first] &, expansions]; expansions ] MinimumCNS[z_?NumberQ, beta_?NumberQ, maxweight_?IntegerQ] := Module[{r, rlist, expansions, mincost, lookup}, If[minimumCNSTableBeta === beta, lookup = minimumCNSTable[z], ( Clear[minimumCNSTable]; minimumCNSTableBeta = beta; ) ]; If[Head[lookup] === List, If[cost[lookup[[1]]] <= maxweight, lookup, {}], ( r = modbase[z, beta]; rlist = possibleDigits[r, beta]; rlist = Select[rlist, Abs[#] <= maxweight &]; expansions = Flatten[Map[MinimumCNS[z, beta, #, maxweight] &, rlist], 1]; mincost = Min[Map[cost, expansions]]; expansions = Select[expansions, cost[#] <= mincost &]; If[Length[expansions] >= 1, minimumCNSTable[z] = expansions ]; expansions ) ] ]; MinimumCNS[z_?NumberQ, beta_?NumberQ] := Module[{standardcost, result}, standardcost = cost[StandardCNS[z, beta]]; result = MinimumCNS[z, beta, standardcost]; If[{z} == Union[result /. CNS :> ExpandCNS[beta]] && Length[Union[Map[cost, result]]] == 1, result, False] ] (*Shortest Expansion: Minimize Length of Expansion, digits = - \ Norm[beta]+1, ... Norm[beta]-1*) ShortestCNS[0, ___] = {CNS[]}; ShortestCNS[z_?NumberQ /; z != 0, beta_?NumberQ, 0] = {}; ShortestCNS[z_?NumberQ, beta_?NumberQ, first_?IntegerQ, maxlength_?IntegerQ] := Module[{expansions}, expansions = ShortestCNS[(z - first)/beta, beta, maxlength - 1]; expansions = Map[Prepend[#, first] &, expansions]; expansions ] ShortestCNS[z_?NumberQ, beta_?NumberQ, maxlength_?IntegerQ] := Module[{r, rlist, expansions, minlength, lookup}, If[shortestCNSTableBeta == beta, lookup = shortestCNSTable[z], ( Clear[shortestCNSTable]; shortestCNSTableBeta = beta; ) ]; If[Head[lookup] === List, If[Length[lookup[[1]]] <= maxlength, lookup, {}], ( r = modbase[z, beta]; rlist = If[r==0,{r},{r,r-norm[beta]}]; expansions = Flatten[Map[ShortestCNS[z, beta, #, maxlength] &, rlist], 1]; minlength = Min[Map[Length, expansions]]; expansions = Select[expansions, Length[#] <= minlength &]; expansions = If[Length[expansions] >= 1, {expansions[[1]]}, {}]; If[Length[expansions] >= 1, shortestCNSTable[z] = expansions ]; expansions ) ] ] ShortestCNS[z_?NumberQ, beta_?NumberQ] := Module[{standardlength, result}, standardlength = Length[StandardCNS[z, beta]]; result = ShortestCNS[z, beta, standardlength]; If[Length[result] == 1 && (result /. CNS :> ExpandCNS[beta]) == {z} && Length[result] <= standardlength, result[[1]], False ] ] listCirclePoints[bound_?NumberQ] := Module[{a, b, result}, result = Flatten[Table[ Union[{a + b*I, a - b*I, -a + b*I, -a - b*I}], {a, 0, Floor[Sqrt[bound]]}, {b, 0, Floor[Sqrt[bound - a^2]]}]] ] listRepresenters[u_CNS, beta_?NumberQ] := Module[{z, bound, r, k, possibleOffsets, candidates}, r = Length[u]; z = u /. CNS -> ExpandCNS[beta]; bound = Floor[(2*(norm[beta] - 1)/Abs[beta]^r Sum[ Abs[beta^k], {k, 0, r - 1}])^2]; possibleOffsets = listCirclePoints[bound]; candidates = Map[z + beta^r*# &, possibleOffsets]; Select[candidates, Length[ShortestCNS[#, beta]] <= r &] ] FindRule[u_CNS, beta_?NumberQ] := Module[{repr, expansions, initials}, repr = listRepresenters[u, beta]; expansions = Map[MinimumCNS[#, beta] &, repr] /. CNS[] -> CNS[0]; initials = Map[Union, expansions /. CNS[a_, ___] -> a]; Intersection @@ initials ] 0 End[] EndPackage[]