Biblioteca unificada em Java (compatível com Java 21+) contendo resolvedores matemáticos e simulação de Monte Carlo para Apoio à Decisão Multicritério (MCDM - Multi-Criteria Decision Making).
Esta biblioteca é o equivalente exato em ecossistema Java das versões Python (sad-mcdm-lib), R (sadMCDM) e JS/TS (sad-mcdm-js), retornando os mesmos resultados matemáticos precisos.
- Zero Dependências Externas: O resolvedor Simplex (Método das Duas Fases) e branch-and-bound binário foram implementados inteiramente em Java puro. Isso torna a biblioteca totalmente portável e independente de dependências JNI nativas (como OR-Tools, Gurobi, CPLEX ou GLPK).
- Estrutura Baseada em Mapas Dinâmicos: A biblioteca utiliza
LinkedHashMap<String, Object>para dados de entrada flexíveis (parâmetros de preferência) e para o retorno das saídas, assemelhando-se às estruturas do Python e R. - Fácil Integração: Compilável diretamente com a ferramenta padrão
javacdo Java.
Todos os arquivos estão sob o pacote sad.mcdm:
sad.mcdm.Simplex: Contém o motor de Programação Linear Simplex de duas fases e Branch-and-Bound.sad.mcdm.Solvers: Implementação dos 9 solvers MCDM como métodos estáticos.sad.mcdm.MonteCarlo: Motor estocástico de simulação para análise de sensibilidade.sad.mcdm.TestSuite: Classe de validação com asserções numéricas.
O projeto inclui um script do PowerShell (build.ps1) para automatizar a compilação e teste local.
Para rodar os testes:
- Abra um console do PowerShell no diretório do projeto.
- Execute o script:
./build.ps1
O console exibirá o status de compilação dos fontes para a pasta bin/ e rodará a classe sad.mcdm.TestSuite imprimindo o resultado das asserções.
Todos os resolvedores matemáticos são expostos como métodos estáticos da classe sad.mcdm.Solvers:
Processo Hierárquico Analítico (AHP) com Média Geométrica de Linhas e Razão de Consistência (CR).
Map<String, Object> resultado = Solvers.solveAHP(matrix, types, preferenceData, criteriaIds, alternativeIds);Best-Worst Method (BWM) com otimização minimax via Simplex Linear nativo.
Map<String, Object> resultado = Solvers.solveBWM(matrix, types, preferenceData, criteriaIds, alternativeIds);Best-Worst Tradeoff (BWT) com interpolação de bisseção de utilidades.
Map<String, Object> resultado = Solvers.solveBWT(matrix, types, preferenceData, criteriaIds, alternativeIds);Família de métodos ELECTRE (suporta ELECTRE I, II e TRI para ordenação de categorias).
Map<String, Object> resultado = Solvers.solveELECTRE(matrix, types, preferenceData, criteriaIds, alternativeIds);Método MACBETH com calibração de escala de atratividade qualitativa semântica baseada em PL.
Map<String, Object> resultado = Solvers.solveMACBETH(matrix, types, preferenceData, criteriaIds, alternativeIds);Métodos PROMETHEE I (parcial), PROMETHEE II (completo) e PROMETHEE V (otimização de portfólio restrita por orçamento através de branch-and-bound binário).
Map<String, Object> resultado = Solvers.solvePROMETHEE(matrix, types, preferenceData, criteriaIds, alternativeIds);Métodos SMARTS (pesos swing informados) e SMARTER (pesos centróides ROC de ordenação ordinal).
Map<String, Object> resultado = Solvers.solveSMARTS_SMARTER(matrix, types, preferenceData, criteriaIds, "smarter");Método TOPSIS baseado na proximidade geométrica das alternativas em relação às soluções ideais positiva e negativa.
Map<String, Object> resultado = Solvers.solveTOPSIS(matrix, types, preferenceData, criteriaIds, alternativeIds);Método VIKOR integrando a utilidade de grupo máxima e o arrependimento individual.
Map<String, Object> resultado = Solvers.solveVIKOR(matrix, types, preferenceData, criteriaIds, alternativeIds);Simulação estocástica de sensibilidade em Java (sad.mcdm.MonteCarlo):
Map<String, Object> mc = MonteCarlo.runMonteCarlo(matrix, types, weights, variationsPct, numSimulations, "topsis", preferenceData, criteriaIds);import sad.mcdm.Solvers;
import java.util.*;
public class Main {
public static void main(String[] args) {
// 3 alternativas, 2 critérios
double[][] matrix = {
{10.0, 100.0},
{20.0, 50.0},
{30.0, 0.0}
};
String[] types = {"benefit", "cost"};
Map<String, Object> preferenceData = new LinkedHashMap<>();
Map<String, Double> weights = new LinkedHashMap<>();
weights.put("1", 50.0);
weights.put("2", 50.0);
preferenceData.put("weights", weights);
int[] criteriaIds = {1, 2};
int[] alternativeIds = {1, 2, 3};
// Executa o TOPSIS
Map<String, Object> res = Solvers.solveTOPSIS(matrix, types, preferenceData, criteriaIds, alternativeIds);
double[] closeness = (double[]) res.get("global_scores");
int[] ranks = (int[]) res.get("ranks");
System.out.println("Pontuações de Proximidade: " + Arrays.toString(closeness));
System.out.println("Rankings das Alternativas: " + Arrays.toString(ranks));
}
}