I am trying to create a matrix with the following constraints.
- The column sum should be between 300 and 390, both values inclusive.
- Row sum should be equal to user-specified values per row.
- No non-zero value in the matrix should be less than 10.
- The count of non-zero values in a given column should not exceed 4.
- The columns should be arranged in a diagonal order.
if UserInput = [427.7, 12.2, 352.7, 58.3, 22.7, 31.9, 396.4, 29.4, 171.5, 474.5, 27.9, 200]
I want output matrix something like this,

Edit 1
I have tried the following approach using Pyomo, however, I got stuck on 5th constraint that column values should be diagonally aligned in the matrix
import sys
import math
import numpy as np
import pandas as pd
from pyomo.environ import *
solverpath_exe= 'glpk-4.65\\w64\\glpsol.exe'
solver=SolverFactory('glpk',executable=solverpath_exe)
# Minimize the following:
# Remaining pieces to be zero for all et values
# The number of cells containg non-zero values
# Constraints
# 1) Column sum, CS, is: 300 <= CS <= 390
# 2) Row sum, RS, is equal to user-specified values, which are present in the E&T ticket column of the file
# 3) Number of non-zero values, NZV, in each column, should be: 0 < NZV <= 4
# 4) The NZV in the matrix should be: NZV >= 10
# 5) The pieces are stacked on top of each other. So, a the cell under a non-zero value cell is zero, than all cells underneath should have zeros.
maxlen = 390
minlen = 300
npiece = 4
piecelen = 10
# Input data: E&T Ticket values
etinput = [427.7, 12.2, 352.7, 58.3, 22.7, 31.9,
396.4, 29.4, 171.5, 474.5, 27.9, 200]
# Create data structures to store values
etnames = [f'et{i}' for i in range(1,len(etinput) + 1)]
colnames = [f'col{i}' for i in range(1, math.ceil(sum(etinput)/minlen))] #+1 as needed
et_val = dict(zip(etnames, etinput))
# Instantiate Concrete Model
model2 = ConcreteModel()
# define variables and set upper bound to 390
model2.vals = Var(etnames, colnames, domain=NonNegativeReals,bounds = (0, maxlen), initialize=0)
# Create Boolean variables
bigM = 10000
model2.y = Var(colnames, domain= Boolean)
model2.z = Var(etnames, colnames, domain= Boolean)
# Minimizing the sum of difference between the E&T Ticket values and rows
model2.minimizer = Objective(expr= sum(et_val[r] - model2.vals[r, c]
for r in etnames for c in colnames),
sense=minimize)
model2.reelconstraint = ConstraintList()
for c in colnames:
model2.reelconstraint.add(sum(model2.vals[r,c] for r in etnames) <= bigM * model2.y[c])
# Set constraints for row sum equal to ET values
model2.rowconstraint = ConstraintList()
for r in etnames:
model2.rowconstraint.add(sum(model2.vals[r, c] for c in colnames) <= et_val[r])
# Set contraints for upper bound of column sums
model2.colconstraint_upper = ConstraintList()
for c in colnames:
model2.colconstraint_upper.add(sum(model2.vals[r, c] for r in etnames) <= maxlen)
# Set contraints for lower bound of column sums
model2.colconstraint_lower = ConstraintList()
for c in colnames:
model2.colconstraint_lower.add(sum(model2.vals[r, c] for r in etnames) + bigM * (1-model2.y[c]) >= minlen)
model2.bool = ConstraintList()
for c in colnames:
for r in etnames:
model2.bool.add(model2.vals[r,c] <= bigM * model2.z[r,c])
model2.npienceconstraint = ConstraintList()
for c in colnames:
model2.npienceconstraint.add(sum(model2.z[r, c] for r in etnames) <= npiece)
# Call solver for model
solver.solve(model2);
# Create dataframe of output
pdtest = pd.DataFrame([[model2.vals[r, c].value for c in colnames] for r in etnames],
index=etnames,
columns=colnames)
pdtest
Output

np.linalg.lstsqfor column sums 395), but you'd have to iterate over combinations. You have 17 equations (12 hard and 7 soft) with 10 unknowns, but you may pick the unknowns, so you have a large, countable number of systems of equations and you may pick the one that satisfies the conditions. Generally, that is not possible unless you are lucky.2**28-1. Skip the ones that do not satisfy the requirements on number of nonzero elements. Usenp.linalg.lstsqfor the other ones. Discard the solutions that do not meet other requirements. But brute-forcing over2**28combinations does not look like a good idea. Better look into simulated annealing for this class of problems.