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.

300 lines
7.7 KiB

  1. package circuitcompiler
  2. import (
  3. "fmt"
  4. "math/big"
  5. "sort"
  6. "strings"
  7. )
  8. type factors []*factor
  9. type factor struct {
  10. typ Token
  11. name string
  12. invert, negate bool
  13. multiplicative [2]int
  14. }
  15. func (f factors) Len() int {
  16. return len(f)
  17. }
  18. func (f factors) Swap(i, j int) {
  19. f[i], f[j] = f[j], f[i]
  20. }
  21. func (f factors) Less(i, j int) bool {
  22. if strings.Compare(f[i].String(), f[j].String()) < 0 {
  23. return false
  24. }
  25. return true
  26. }
  27. func (f factor) String() string {
  28. if f.typ == CONST {
  29. return fmt.Sprintf("(const fac: %v)", f.multiplicative)
  30. }
  31. str := f.name
  32. if f.invert {
  33. str += "^-1"
  34. }
  35. if f.negate {
  36. str = "-" + str
  37. }
  38. return fmt.Sprintf("(\"%s\" fac: %v)", str, f.multiplicative)
  39. }
  40. func (f factors) clone() (res factors) {
  41. res = make(factors, len(f))
  42. for k, v := range f {
  43. res[k] = &factor{multiplicative: v.multiplicative, typ: v.typ, name: v.name, invert: v.invert, negate: v.negate}
  44. }
  45. return
  46. }
  47. func (f factors) normalizeAll() {
  48. for i, _ := range f {
  49. f[i].multiplicative = normalizeFactor(f[i].multiplicative)
  50. }
  51. }
  52. // find Least Common Multiple (LCM) via GCD
  53. func LCMsmall(a, b int) int {
  54. result := a * b / GCD(a, b)
  55. return result
  56. }
  57. func extractFactor(f factors) (factors, [2]int) {
  58. lcm := f[0].multiplicative[1]
  59. for i := 1; i < len(f); i++ {
  60. lcm = LCMsmall(f[i].multiplicative[1], lcm)
  61. }
  62. for i := 0; i < len(f); i++ {
  63. f[i].multiplicative[0] = (lcm / f[i].multiplicative[1]) * f[i].multiplicative[0]
  64. }
  65. gcd := f[0].multiplicative[0]
  66. for i := 1; i < len(f); i++ {
  67. gcd = GCD(f[i].multiplicative[0], gcd)
  68. }
  69. for i := 0; i < len(f); i++ {
  70. f[i].multiplicative[0] = f[i].multiplicative[0] / gcd
  71. f[i].multiplicative[1] = 1
  72. }
  73. return f, [2]int{gcd, lcm}
  74. }
  75. func factorsSignature(leftFactors, rightFactors factors) (sig MultiplicationGateSignature, extractedLeftFactors, extractedRightFactors factors) {
  76. leftFactors = leftFactors.clone()
  77. rightFactors = rightFactors.clone()
  78. leftFactors.normalizeAll()
  79. var extractedFacLeft [2]int
  80. leftFactors, extractedFacLeft = extractFactor(leftFactors)
  81. sort.Sort(leftFactors)
  82. hasher.Reset()
  83. for _, fac := range leftFactors {
  84. hasher.Write([]byte(fac.String()))
  85. }
  86. leftNum := new(big.Int).SetBytes(hasher.Sum(nil))
  87. rightFactors.normalizeAll()
  88. var extractedFacRight [2]int
  89. rightFactors, extractedFacRight = extractFactor(rightFactors)
  90. sort.Sort(rightFactors)
  91. hasher.Reset()
  92. for _, fac := range rightFactors {
  93. hasher.Write([]byte(fac.String()))
  94. }
  95. rightNum := new(big.Int).SetBytes(hasher.Sum(nil))
  96. //we did all this, because multiplication is commutativ, and we want the signature of a
  97. //mulitplication gate factorsSignature(a,b) == factorsSignature(b,a)
  98. leftNum.Add(leftNum, rightNum)
  99. res := normalizeFactor(mul2DVector(extractedFacLeft, extractedFacRight))
  100. return MultiplicationGateSignature{identifier: leftNum.String()[:16], commonExtracted: res}, leftFactors, rightFactors
  101. }
  102. func lengthOfLongestSlice(a, b factors) int {
  103. if len(a) > len(b) {
  104. return len(a)
  105. }
  106. return len(b)
  107. }
  108. //multiplies factor elements and returns the result
  109. //in case the factors do not hold any constants and all inputs are distinct, the output will be the concatenation of left+right
  110. func mulFactors(leftFactors, rightFactors factors) (result factors) {
  111. if len(leftFactors) < len(rightFactors) {
  112. tmp := leftFactors
  113. leftFactors = rightFactors
  114. rightFactors = tmp
  115. }
  116. for i, left := range leftFactors {
  117. for _, right := range rightFactors {
  118. if left.typ == CONST && right.typ == IN {
  119. leftFactors[i] = &factor{typ: IN, name: right.name, negate: Xor(left.negate, right.negate), invert: right.invert, multiplicative: mul2DVector(right.multiplicative, left.multiplicative)}
  120. continue
  121. }
  122. if right.typ == CONST && left.typ == IN {
  123. leftFactors[i] = &factor{typ: IN, name: left.name, negate: Xor(left.negate, right.negate), invert: left.invert, multiplicative: mul2DVector(right.multiplicative, left.multiplicative)}
  124. continue
  125. }
  126. if right.typ&left.typ == CONST {
  127. leftFactors[i] = &factor{typ: CONST, negate: Xor(right.negate, left.negate), multiplicative: mul2DVector(right.multiplicative, left.multiplicative)}
  128. continue
  129. }
  130. //tricky part here
  131. //this one should only be reached, after a true mgate had its left and right braches computed. here we
  132. //a factor can appear at most in quadratic form. we reduce terms a*a^-1 here.
  133. if right.typ&left.typ == IN {
  134. if left.name == right.name {
  135. if right.invert != left.invert {
  136. leftFactors[i] = &factor{typ: CONST, negate: Xor(right.negate, left.negate), multiplicative: mul2DVector(right.multiplicative, left.multiplicative)}
  137. continue
  138. }
  139. }
  140. //rightFactors[i] = factor{typ: CONST, negate: Xor(facRight.negate, facLeft.negate), multiplicative: mul2DVector(facRight.multiplicative, facLeft.multiplicative)}
  141. //continue
  142. }
  143. panic("unexpected. If this errror is thrown, its probably brcause a true multiplication gate has been skipped and treated as on with constant multiplication or addition ")
  144. }
  145. }
  146. return leftFactors
  147. }
  148. //returns the absolute value of a signed int and a flag telling if the input was positive or not
  149. //this implementation is awesome and fast (see Henry S Warren, Hackers's Delight)
  150. func abs(n int) (val int, positive bool) {
  151. y := n >> 63
  152. return (n ^ y) - y, y == 0
  153. }
  154. //adds two factors to one iff they are both are constants or of the same variable
  155. func addFactor(facLeft, facRight factor) (couldAdd bool, sum factor) {
  156. if facLeft.typ&facRight.typ == CONST {
  157. var a0, b0 = facLeft.multiplicative[0], facRight.multiplicative[0]
  158. if facLeft.negate {
  159. a0 *= -1
  160. }
  161. if facRight.negate {
  162. b0 *= -1
  163. }
  164. absValue, positive := abs(a0*facRight.multiplicative[1] + facLeft.multiplicative[1]*b0)
  165. return true, factor{typ: CONST, negate: !positive, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}}
  166. }
  167. if facLeft.typ&facRight.typ == IN && facLeft.invert == facRight.invert && facLeft.name == facRight.name {
  168. var a0, b0 = facLeft.multiplicative[0], facRight.multiplicative[0]
  169. if facLeft.negate {
  170. a0 *= -1
  171. }
  172. if facRight.negate {
  173. b0 *= -1
  174. }
  175. absValue, positive := abs(a0*facRight.multiplicative[1] + facLeft.multiplicative[1]*b0)
  176. return true, factor{typ: IN, invert: facRight.invert, name: facRight.name, negate: !positive, multiplicative: [2]int{absValue, facLeft.multiplicative[1] * facRight.multiplicative[1]}}
  177. }
  178. return false, factor{}
  179. }
  180. //returns the reduced sum of two input factor arrays
  181. //if no reduction was done (worst case), it returns the concatenation of the input arrays
  182. func addFactors(leftFactors, rightFactors factors) factors {
  183. var found bool
  184. res := make(factors, 0, len(leftFactors)+len(rightFactors))
  185. for _, facLeft := range leftFactors {
  186. found = false
  187. for i, facRight := range rightFactors {
  188. var sum factor
  189. found, sum = addFactor(*facLeft, *facRight)
  190. if found {
  191. rightFactors[i] = &sum
  192. break
  193. }
  194. }
  195. if !found {
  196. res = append(res, facLeft)
  197. }
  198. }
  199. for _, val := range rightFactors {
  200. if val.multiplicative[0] != 0 {
  201. res = append(res, val)
  202. }
  203. }
  204. return res
  205. }
  206. // -4/-5 -> 4/5 ; 5/-7 -> -5/7 ; 6 /2 -> 3 / 1
  207. func normalizeFactor(b [2]int) [2]int {
  208. resa, signa := abs(b[0])
  209. resb, signb := abs(b[1])
  210. gcd := GCD(resa, resb)
  211. if Xor(signa, signb) {
  212. resa = -resa
  213. }
  214. return [2]int{resa / gcd, resb / gcd}
  215. }
  216. //naive component multiplication
  217. func mul2DVector(a, b [2]int) [2]int {
  218. return [2]int{a[0] * b[0], a[1] * b[1]}
  219. }
  220. // find Least Common Multiple (LCM) via GCD
  221. func LCM(a, b int, integers ...int) int {
  222. result := a * b / GCD(a, b)
  223. for i := 0; i < len(integers); i++ {
  224. result = LCM(result, integers[i])
  225. }
  226. return result
  227. }
  228. //euclidean algo to determine greates common divisor
  229. func GCD(a, b int) int {
  230. for b != 0 {
  231. t := b
  232. b = a % b
  233. a = t
  234. }
  235. return a
  236. }