// Vector by matrix multiplication has a pattern of:
        // float2(dot(m_row1, v), dot(m_row2, v))
        // float3(dot(m_row1, v), dot(m_row2, v), dot(m_row3, v))
        // float4(dot(m_row1, v), dot(m_row2, v), dot(m_row3, v), dot(m_row4, v))
        public MatrixMultiplicationContext TryGetMultiplicationGroup(IList <HlslTreeNode> components)
        {
            const bool allowMatrix = true;

            if (!(components[0] is DotProductOperation firstDot))
            {
                return(null);
            }

            int dimension = firstDot.X.Length;

            if (components.Count < dimension)
            {
                return(null);
            }

            GroupNode firstMatrixRow = TryGetMatrixRow(firstDot, firstDot, 0);

            if (firstMatrixRow == null)
            {
                return(null);
            }

            GroupNode vector = firstDot.X == firstMatrixRow
                    ? firstDot.Y
                    : firstDot.X;

            var matrixRows = new List <GroupNode>();

            matrixRows.Add(firstMatrixRow);
            for (int i = 1; i < components.Count; i++)
            {
                if (!(components[i] is DotProductOperation nextDot))
                {
                    break;
                }

                GroupNode matrixRow = TryGetMatrixRow(nextDot, firstDot, i);
                if (matrixRow == null)
                {
                    break;
                }

                GroupNode nextVector = nextDot.X == matrixRow
                    ? nextDot.Y
                    : nextDot.X;
                if (!NodeGrouper.AreNodesEquivalent(vector, nextVector))
                {
                    break;
                }

                matrixRows.Add(matrixRow);
            }

            if (matrixRows.Count < 2)
            {
                return(null);
            }

            ConstantDeclaration matrix = TryGetMatrixDeclaration(matrixRows);

            if (matrix == null)
            {
                return(null);
            }

            bool matrixByVector = firstMatrixRow.Inputs
                                  .Cast <RegisterInputNode>()
                                  .All(row => row.ComponentIndex == 0);

            vector = SwizzleVector(vector, firstMatrixRow, matrixByVector);

            return(new MatrixMultiplicationContext(vector, matrix, matrixByVector, matrixRows.Count));
        }