pub version

✨ About

Flutter package for practical Multi-Criteria Decision Making (MCDM). Providing algorithms such as AHP, SAW, and TOPSIS to help developers perform weighting, evaluation, and ranking of alternatives easily and accurately within their Flutter applications.

Status Algorithm Available in version
βœ… AHP (Analytic Hierarchy Process) 1.0.0
βœ… SAW (Simple Additive Weighting) 1.1.0
βœ… TOPSIS (Technique for Order Preference by Similarity to Ideal Solution) 1.2.0
Feature Available in version
Self-explaining (detailed) results with toJson() 2.0.0
Weight sensitivity analysis & rank reversal check 2.0.0
Pure Dart core (decision_making_core) 2.0.0

🎯 Typical Use Cases

Suitable for building decision support features such as:

  • HR candidate or promotion selection
  • Vendor or project evaluation
  • Scholarship or student ranking
  • Feature prioritization in product management
  • Internal corporate decision-making systems
  • Recommendation or comparison apps

πŸ“¦ Installation

flutter pub add flutter_decision_making
import 'package:flutter_decision_making/flutter_decision_making.dart';

Need the algorithms without Flutter (CLI, server, Dart backend)? Use the pure Dart package decision_making_core.


πŸ“š Usage Guide

You can use this package in two ways depending on your needs:

  1. Using all algorithms together
    Initialize the FlutterDecisionMaking class to access all available algorithms.
late FlutterDecisionMaking _decisionMaking;
AhpResult? _ahpResult;
List<WeightedDecisionResult>? _sawResult;
List<WeightedDecisionResult>? _topsisResult;

@override
void initState() {
  super.initState();
  _decisionMaking = FlutterDecisionMaking();
}

// Usage example:
// for AHP
_ahpResult = await _decisionMaking.ahp.getAhpResult(...);

// for SAW
_sawResult = await _decisionMaking.saw.getSawResult(...);

// for TOPSIS
_topsisResult = await _decisionMaking.topsis.getTopsisResult(...);

This is the easiest way if you want to use multiple algorithms in your project.

  1. Using a specific algorithm only

If you only need a single algorithm (e.g., AHP), you can import and initialize it directly:

late AHP _ahp;
AhpResult? _ahpResult;

@override
void initState() {
  super.initState();
  _ahp = AHP();
}

// Usage example:
_ahpResult = await _ahp.getAhpResult(...);


πŸ” Explainable Results

Every algorithm can return all intermediate steps, not only the final ranking. Useful for reports, audits and teaching.

final saw = await _decisionMaking.saw.getSawDetailedResult(matrix: matrix);
saw.normalizedMatrix;   // r_ij
saw.normalizedWeights;  // w_j (sum = 1)
saw.weightedMatrix;     // v_ij
saw.scores;             // final scores and ranks

final topsis = await _decisionMaking.topsis.getTopsisDetailedResult(matrix: topsisMatrix);
topsis.positiveIdeal;   // A+
topsis.negativeIdeal;   // A-
topsis.separationPlus;  // D+
topsis.separationMinus; // D-

final ahp = await _decisionMaking.ahp.getAhpDetailedResult(...);
ahp.criteriaEvaluation; // comparison/normalized matrix, weights, lambda max, CI, RI, CR

final json = saw.toJson(); // every detailed result can be serialized

The existing getSawResult, getTopsisResult and getAhpResult are unchanged.


πŸ§ͺ Sensitivity Analysis & Rank Reversal (SAW, TOPSIS)

Check how stable a ranking is.

final result = await _decisionMaking.saw.analyzeSensitivity(matrix: matrix, delta: 0.10);

result.isStable;              // false if any perturbation or removal changes the order
result.sensitivityCases;      // each criterion weight +/- 10% (relative), others rescaled
result.rankReversalCases;     // each alternative removed in turn (needs 3+ alternatives)

Rank reversal is detected, not prevented. Results depend on delta and on the normalization method of each algorithm. Skipped cases (for example fewer than 3 alternatives) are reported with a reason and are not counted as unstable.


πŸ“– Algorithm Docs

For details on how to use the algorithm, you can visit the following documentation.

Link Description
AHP Doc If you need a method that is able to determine weights accurately through pairwise comparisons, validate the consistency of assessments, and work well on subjective or multilevel criteria.
SAW Doc If you need a simple, fast, easy to calculate, and easy to implement method for ranking alternatives based on criteria weights and values.
TOPSIS Doc If you need a method that ranks alternatives based on their distance to the ideal best and ideal worst solutions, providing a more discriminative and robust decision-making result.

The wiki pages describe each algorithm. For detailed results, sensitivity analysis and useIsolate, see the sections above.


πŸ“ˆ Performance Profiling

Major method logs:

  • Start and end timestamps.
  • Execution duration (in milliseconds).

Useful for debugging and optimization during development.


⚑ When to Use Isolates (useIsolate)

By default all calculations run on the main thread (useIsolate: false). Isolates are opt-in via useIsolate: true.

Measured on Apple Silicon (macOS), --profile mode, public API, median min–max of 10 runs after 3 warm-ups:

Case (alternatives Γ— criteria) Main thread (ms) Isolate, warm (ms) Main thread blocked (ms)
SAW 80 Γ— 25 0.19 0.18–0.35 4.35 3.01–5.86 0.85 0.00–3.03
SAW 2000 Γ— 50 8.71 8.39–12.27 449.24 411.99–477.15 244.23 219.73–262.51
TOPSIS 80 Γ— 25 0.52 0.50–0.55 4.02 3.33–6.18 0.80 0.00–3.34
TOPSIS 2000 Γ— 50 47.53 40.32–52.14 526.39 464.34–605.88 277.99 223.17–306.31
AHP 80 Γ— 10 31.71 31.21–52.50 51.01 47.90–66.97 25.84 23.09–39.94

"Main thread blocked" is estimated with an event-loop lag monitor; values near 0 mean the blocking was below its detection threshold (about 1 ms), not that it is exactly zero. Mobile devices will be slower than these numbers, so profile on your target device.

Recommendation: keep the default. Sending data to an isolate costs more (serialization) than the calculation itself in every case measured. Use useIsolate: true only if you must keep very large calculations off the UI thread and accept a longer total time. Note that AHP needs n(n-1)/2 pairwise judgments per matrix, so very large AHP inputs are rarely practical for human evaluators.


⬆️ Upgrading from 1.x

  • Isolates are no longer used automatically. Pass useIsolate: true if you relied on that behaviour.
  • DecisionIsolateMain and the isolate message/worker types are no longer exported from the main library.
  • TOPSIS in 1.2.0 returned wrong rankings above 80 alternatives or 25 criteria. Upgrade if you use TOPSIS with large inputs.

See the CHANGELOG for details.


πŸ’‘ Want Another Algorithm?

We are continuously improving this package πŸš€

If you would like to see a new algorithm (e.g., WP, ELECTRE, MOORA, PROMETHEE, etc.) added:

πŸ‘‰ Please open a discussion: GitHub Discussions

⚠️ Note: New algorithms will be prioritized based on:

  • Community interest
  • Contribution support (PRs are welcome!)
  • Maintainer availability

Contributions are highly appreciated πŸ™Œ


🎁 Support Me

Ko-Fi Saweria Badge


πŸ™‹β€β™‚οΈ Contributing

We welcome all contributions and suggestions!

πŸ‘‰ Open an issue or submit a pull request at GitHub Repo


Star History

Star History Chart

Libraries

core/decision_making_enums
core/decision_making_helper
core/decision_making_performance_profiling
core/decision_making_utils
core/isolate/decision_isolate_main
core/isolate/decision_isolate_message
core/isolate/decision_isolate_worker
core/isolate/decision_processing_isolate_command
core/shared/dto/weighted_decision_alternative_dto
core/shared/dto/weighted_decision_criteria_dto
core/shared/dto/weighted_decision_matrix_dto
core/shared/dto/weighted_decision_rating_dto
core/shared/dto/weighted_decision_result_dto
core/shared/entity/weighted_decision_alternative
core/shared/entity/weighted_decision_criteria
core/shared/entity/weighted_decision_matrix
core/shared/entity/weighted_decision_rating
core/shared/entity/weighted_decision_result
core/shared/interface/generate_weighted_decision_matrix_isolate
core/shared/interface/weighted_decision_matrix_mixin
core/shared/mapper/weighted_decision_alternative_mapper
core/shared/mapper/weighted_decision_criteria_mapper
core/shared/mapper/weighted_decision_matrix_mapper
core/shared/mapper/weighted_decision_rating_mapper
core/shared/mapper/weighted_decision_result_mapper
feature/ahp/data/datasource/ahp_calculate_eigen_vector_alternative_isolated
feature/ahp/data/datasource/ahp_calculate_eigen_vector_criteria_isolated
feature/ahp/data/datasource/ahp_check_consistency_ratio_isolated
feature/ahp/data/datasource/ahp_final_score_isolated
feature/ahp/data/datasource/ahp_input_pairwise_matrix_alternative_with_compute
feature/ahp/data/datasource/ahp_local_datasource
feature/ahp/data/datasource/ahp_result_pairwise_matrix_alternative_isolated
feature/ahp/data/datasource/ahp_result_pairwise_matrix_criteria_isolated
feature/ahp/data/dto/ahp_consistency_ratio_dto
feature/ahp/data/dto/ahp_hierarchy_dto
feature/ahp/data/dto/ahp_item_dto
feature/ahp/data/dto/ahp_result_detail_dto
feature/ahp/data/dto/ahp_result_dto
feature/ahp/data/dto/pairwise_comparison_alternative_input_dto
feature/ahp/data/dto/pairwise_comparison_input_dto
feature/ahp/data/mapper/ahp_consistency_ratio_mapper
feature/ahp/data/mapper/ahp_hierarchy_mapper
feature/ahp/data/mapper/ahp_item_mapper
feature/ahp/data/mapper/ahp_result_detail_mapper
feature/ahp/data/mapper/ahp_result_mapper
feature/ahp/data/mapper/pairwise_comparison_alternative_input_mapper
feature/ahp/data/mapper/pairwise_comparison_input_mapper
feature/ahp/data/repository_impl/ahp_repository_impl
feature/ahp/domain/entities/ahp_comparison_scale
feature/ahp/domain/entities/ahp_consistency_ratio
feature/ahp/domain/entities/ahp_hierarchy
feature/ahp/domain/entities/ahp_identification
feature/ahp/domain/entities/ahp_item
feature/ahp/domain/entities/ahp_result
feature/ahp/domain/entities/ahp_result_detail
feature/ahp/domain/entities/pairwise_alternative_input
feature/ahp/domain/entities/pairwise_comparison_input
feature/ahp/domain/repository/ahp_repository
feature/ahp/domain/usecase/ahp_calculate_final_score_usecase
feature/ahp/domain/usecase/ahp_generate_hierarchy_usecase
feature/ahp/domain/usecase/ahp_generate_pairwise_alternative_input_usecase
feature/ahp/domain/usecase/ahp_generate_pairwise_criteria_input_usecase
feature/ahp/domain/usecase/ahp_identification_usecase
feature/ahp/presentation/ahp
feature/ahp/presentation/ahp_utils
feature/saw/data/datasource/normalize_saw_matrix_isolate
feature/saw/data/datasource/saw_local_datasource
feature/saw/data/datasource/saw_local_datasource_impl
feature/saw/data/repository_impl/saw_repository_impl
feature/saw/domain/repository/saw_repository
feature/saw/domain/usecase/saw_calculate_result_usecase
feature/saw/domain/usecase/saw_calculate_result_with_existing_matrix_usecase
feature/saw/domain/usecase/saw_generate_pairwise_matrix_usecase
feature/saw/presentation/saw
feature/saw/presentation/saw_utils
feature/topsis/data/datasource/normalize_euclidean_matrix_isolate
feature/topsis/data/datasource/topsis_local_datasource
feature/topsis/data/datasource/topsis_local_datasource_impl
feature/topsis/data/dto/topsis_raw_matrix_dto
feature/topsis/data/mapper/topsis_raw_matrix_mapper
feature/topsis/data/repository_impl/topsis_repository_impl
feature/topsis/domain/entities/topsis_ideal_value
feature/topsis/domain/entities/topsis_matrix
feature/topsis/domain/entities/topsis_raw_matrix
feature/topsis/domain/repository/topsis_repository
feature/topsis/domain/usecase/calculate_topsis_result_usecase
feature/topsis/domain/usecase/calculate_topsis_result_with_existing_matrix_usecase
feature/topsis/domain/usecase/generate_topsis_matrix_usecase
feature/topsis/presentation/topsis
feature/topsis/presentation/topsis_utils
flutter_decision_making