```\nFile: StableMath.sol\n    function _calculateInvariant(\n        uint256 amplificationParameter,\n        uint256[] memory balances,\n        bool roundUp\n    ) internal pure returns (uint256) {\n        /**********************************************************************************************\n        // invariant                                                                                 //\n        // D = invariant                                                  D^(n+1)                    //\n        // A = amplification coefficient      A  n^n S + D = A D n^n + -----------                   //\n        // S = sum of balances                                             n^n P                     //\n        // P = product of balances                                                                   //\n        // n = number of tokens                                                                      //\n        *********x************************************************************************************/\n\n        unchecked {\n            // We support rounding up or down.\n            uint256 sum = 0;\n            uint256 numTokens = balances.length;\n            for (uint256 i = 0; i < numTokens; i++) {\n                sum = sum.add(balances[i]);\n            }\n            if (sum == 0) {\n                return 0;\n            }\n\n            uint256 prevInvariant = 0;\n            uint256 invariant = sum;\n            uint256 ampTimesTotal = amplificationParameter * numTokens;\n\n            for (uint256 i = 0; i < 255; i++) {\n                uint256 P_D = balances[0] * numTokens;\n                for (uint256 j = 1; j < numTokens; j++) {\n                    P_D = Math.div(Math.mul(Math.mul(P_D, balances[j]), numTokens), invariant, roundUp);\n                }\n                prevInvariant = invariant;\n                invariant = Math.div(\n                    Math.mul(Math.mul(numTokens, invariant), invariant).add(\n                        Math.div(Math.mul(Math.mul(ampTimesTotal, sum), P_D), _AMP_PRECISION, roundUp)\n                    ),\n                    Math.mul(numTokens + 1, invariant).add(\n                        // No need to use checked arithmetic for the amp precision, the amp is guaranteed to be at least 1\n                        Math.div(Math.mul(ampTimesTotal - _AMP_PRECISION, P_D), _AMP_PRECISION, !roundUp)\n                    ),\n                    roundUp\n                );\n\n                if (invariant > prevInvariant) {\n                    if (invariant - prevInvariant <= 1) {\n                        return invariant;\n                    }\n                } else if (prevInvariant - invariant <= 1) {\n                    return invariant;\n                }\n            }\n        }\n\n        revert CalculationDidNotConverge();\n    }\n```\n