Update: Putting together pieces from several sources (links below) to identify the largest contiguous rectangle in a binary matrix:
ClearAll[poP, stutteringAccumulate, largestRectangleInHistogram, maxRectangle]
SetAttributes[poP, HoldAllComplete];
poP[a_] := Module[{b}, If[EmptyQ[a], False, b = Last[a]; Set[a, Most[a]]; b]]
stutteringAccumulate = FoldList[#2 #1 + #2 &, #] &;
largestRectangleInHistogram = Module[{max = 0, a = Join[{-1}, #, { -1}], n = 2 + Length@#,
stack = {1}, h, area, i, index = 1, height = 0},
For[i = 1, i <= n, ++i,
While[a[[i]] < a[[Last@stack]],
h = a[[poP[stack]]];
area = h (i - Last[stack] - 1); max = Max[max, area];
If[max > area, index = index; height = height, index = i; height = h];
]; AppendTo[stack, i]];
{height, {# - 1 - max/height, # - 2} &@index, max}] &;
maxRectangle[mat_] := Module[{lr = largestRectangleInHistogram /@ stutteringAccumulate[mat],
l = List /@ Range[Length@mat]},
{#4 - {# - 1, 0}, #2, #3} & @@ MaximalBy[Join[lr, l, 2], Last][[1]]];
Examples:
mat = {{1, 1, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 1}, {0, 0, 0, 1, 1, 1}, {1, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}};
Construct a matrix of histograms:
histograms = stutteringAccumulate @ mat
{{1, 1, 1, 1, 0, 0}, {2, 2, 2, 2, 1, 1}, {0, 0, 0, 3, 2, 2}, {1, 1, 0,
4, 3, 3}, {2, 2, 1, 5, 4, 4}, {3, 3, 2, 6, 5, 5}}
Find the largest rectangle for each row of histograms
:
largestrecs = largestRectangleInHistogram /@ histograms
{{1, {1, 4}, 4}, {2, {1, 4}, 8}, {2, {4, 6}, 6}, {3, {4, 6},
9}, {4, {4, 6}, 12}, {5, {4, 6}, 15}}
Pick from largestrecs
the one with largest area:
{rows, cols, area} = maxRectangle[mat]
{{2, 6}, {4, 6}, 15}
Row[Labeled[##, Top] & @@@ Transpose[{MatrixForm /@ {mat, histograms,
MapAt[Style[#, Red, Bold] &, mat, Span @@@ maxRectangle[mat][[;; 2]]]},
{"mat", "histograms", "max rectangle"}}]]

Row[Labeled[BarChart[#, ImageSize -> 100,
Background -> If[maxRectangle[mat][[-1]] ==
largestRectangleInHistogram[#][[-1]], LightBlue, White]],
Style[largestRectangleInHistogram@#, 12], Top] & /@ histograms, Spacer[5]]

With SeedRandom[1]; mat = RandomInteger[1, {20, 40}];
as input
maxRectangle[mat]
{{17, 20}, {32, 33}, 8}
MatrixForm @ MapAt[Style[#, Red, Bold] &, mat, Span @@@ maxRectangle[mat][[;; 2]]]

Grid[Partition[Labeled[BarChart[#, ImageSize -> 100,
Background -> If[maxRectangle[mat][[-1]] == largestRectangleInHistogram[#][[-1]],
LightBlue, White]], Style[largestRectangleInHistogram@#, 10], Top] & /@
(stutteringAccumulate@mat), 10]]

SeedRandom[123]
dta = RandomInteger[10, 50];
lr = largestRectangleInHistogram[dta];
BarChart[dta, BarSpacing -> 0,
ChartLabels -> Placed[Range@Length@dta, Axis], ImageSize -> Large,
PlotLabel -> Style[lr, 16],
Epilog -> {EdgeForm[Red], FaceForm[Opacity[.5, Red]],
Rectangle @@ (Transpose[{lr[[2]], {0, lr[[1]]}}] + {{-1/2, 0}, {1/2, 0}}) }]

Sources:
The idea of using an increasing stack to find the largest rectangle in a histogram and implementation is from this answer by Pei. The function largestRectangleInHistogram
above is a Mathematica implementation of Pei's python function largestRectangleArea
which is modified to return the column indices and the height in addition to the area of the largest rectangle.
The function poP
is a slightly modified version of Pop
from rosettacode - Stack.
The function stutteringAccumulate
is from the posts by ciao and by Chip Hurst.
Okkes's links to Tushar Roy's YouTube videos has been extremely useful; especially, Maximum Rectangular Area in Histogram and Maximum Size Rectangle of All 1's Dynamic Programming.
Update 2: Dealing with non-necessarily-contiguous case for small matrices:
sa = SparseArray[mat];
al = DeleteCases[sa["AdjacencyLists"], {}];
nzprows = Union@sa["NonzeroPositions"][[All, 1]];
rowindices = MaximalBy[Subsets[nzprows, {2, Infinity}],
Length[#] Length[Intersection @@ #] &@al[[#]] &, 10];
rowscols = {#, Intersection @@ al[[#]]} & /@ rowindices;
Grid[Prepend[{## & @@ #, Times @@ Length /@ #} & /@ rowscols,
{"rows", "columns", "area"}], Dividers -> All] // TeXForm
$\begin{array}{|c|c|c|}
\hline
\text{rows} & \text{columns} & \text{area} \\
\hline
\{2,4,5,6\} & \{1,2,4,5,6\} & 20 \\
\hline
\{2,5,6\} & \{1,2,3,4,5,6\} & 18 \\
\hline
\{1,2,5,6\} & \{1,2,3,4\} & 16 \\
\hline
\{2,4,5\} & \{1,2,4,5,6\} & 15 \\
\hline
\{2,4,6\} & \{1,2,4,5,6\} & 15 \\
\hline
\{4,5,6\} & \{1,2,4,5,6\} & 15 \\
\hline
\{1,2,4,5,6\} & \{1,2,4\} & 15 \\
\hline
\{2,3,4,5,6\} & \{4,5,6\} & 15 \\
\hline
\{2,5\} & \{1,2,3,4,5,6\} & 12 \\
\hline
\{2,6\} & \{1,2,3,4,5,6\} & 12 \\
\hline
\end{array}$
Original answer:
A brute force approach:
mat = {{1, 1, 1, 1, 0, 0}, {1, 1, 1, 1, 1, 1}, {0, 0, 0, 1, 1, 1}, {1, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}};
pairs = Transpose /@ MaximalBy[DeleteDuplicates[CoordinateBounds /@
Subsets[SparseArray[mat]["NonzeroPositions"], {2}]],
Min[#] Total[#, 2] &@mat[[## & @@ Span @@@ #]] &]
{{{2, 4}, {6, 6}}}
mat
is an adjacency matrix of a graph, you might be looking for a maximal complete subgraph or a clique. Szabolcs' package"IGraphM`"
has tools for that... $\endgroup$FindClique
, then filter for blocks that also have 1s on the diagonal. $\endgroup$FindClique
, remove every row/column that has a 0 on the diagonal. $\endgroup$