[go: up one dir, main page]

Skip to content

Advance math is a comprehensive Dart library that enriches mathematical programming in Dart with a wide range of features beyond vectors and matrices.

License

Notifications You must be signed in to change notification settings

gameticharles/advance_math

Repository files navigation

Advance Math Library for Dart

Pub package Null Safety Likes Points Popularity SDK Version

Last Commits Pull Requests Code size License

Stars Forks Github watchers Issues

Advance math is a comprehensive Dart library that enriches mathematical programming in Dart with a wide range of features beyond vectors and matrices. Offering functionality for complex numbers, advanced linear algebra, statistics, geometry, and more. The library opens up new possibilities for mathematical computation and data analysis. Whether you're developing a cutting-edge machine learning application, or simply need to perform calculations with complex numbers. It also provides the tools you need in a well-organized and easy-to-use package.

Features

  • Basic statistics: Statistics operations like mean, median, mode, min, max, variance, standardDeviation, quartiles,permutations, combinations, greatest common divisor(gcd), least common multiple(lcm).
  • Convert number types to words. It also supports to currency formats for cheques and ordinal words representations.
  • Morse code translations for encoding and decoding.
  • Logarithmic operations: natural logarithm of a number, base-10 logarithm and logarithm of a number to a given base.
  • Support angle conversion (degrees, minutes, seconds, radians, gradians, DMS).
  • Trigonometry: It provides computation on all the trigonometric functions on the angle. These includes inverse and hyperbolic function (sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, sec, csc, cot, asec, acsc, acot, sech, csch, coth, asech, acsch, acoth, vers, covers, havers, exsec, excsc).
  • Angle operation: Supports addition, subtraction, multiplication, and division. Also supports comparisons, normalize, interpolation, and small-differencing on angles.
  • Geometry: Geometries like Point, Line, Polygon, Circle, Triangle, SphericalTriangle, etc with specific functionalities and methods are implemented.
  • Polynomial functions: Solve and find roots of a function to any degree (including Linear, Quadratic, Cubic, Quartic etc).
  • Roman numerals: Convert roman numerals to integers and vice versa. It also supports basic arithmetic operations and comparisons.
  • Matrix creation, filling and generation: Methods for filling the matrix with specific values or generating matrices with certain properties, such as zero, ones, identity, diagonal, list, or random matrices.
    • Import and export matrices to and from other formats (e.g., CSV, JSON, binary)
    • Matrix operations: Implement common matrix operations such as addition, subtraction, multiplication (element-wise and matrix-matrix), and division (element-wise) etc.
    • Matrix transformation methods: Add methods for matrix transformations, such as transpose, inverse, pseudoInverse, and rank etc.
    • Matrix manipulation (concatenate, sort, removeRow, removeRows, removeCol, removeCols, reshape, swapping rows and columns etc.)
    • Statistical methods: Methods for calculating statistical properties of the matrix, such as min, max, sum, mean, median, mode, skewness, standard deviation, and variance.
    • Element-wise operations: Methods for performing element-wise operations on the matrix, such as applying a function to each element or filtering elements based on a condition.
    • Solving linear systems of equations (Using Inverse Matrix, LU Decomposition,Gauss-Jordan Elimination, Ridge Regression, Gauss Elimination, Least Squares, Jacobi, Successive Over-Relaxation (SOR), Gauss-Seidel method, Gram Schmidt, Conjugate Gradient, Montante's Method (Bareiss algorithm) and Cramers Rule)
    • Solve matrix decompositions like LU decomposition, QR decomposition, LQ decomposition, Cholesky, Singular Value Decomposition (SVD) with different algorithms Crout's, Doolittle, Gauss Elimination Method, Gram Schmidt, Householder, Partial and Complete Pivoting, etc.
    • Matrix slicing and partitioning: Methods for extracting sub-Matrices or slices from the matrix.
    • Matrix concatenation and stacking: Methods for concatenating or stacking matrices horizontally or vertically.
    • Matrix norms: Methods for calculating matrix norms, such as L1 (Marathan), L2 (Euclidean), and infinity norms.
    • Determine the properties of a matrix.
    • From the matrix, row and columns of the matrix are iterables and also iterate on every element.
    • Eigen values and vectors.
  • Supports vectors, complex numbers and complex vectors with most of the basic functionalities and operations.

Todo

  • Implement Expression
  • Improve speed and performance

Usage

Import the library

import 'package:advance_math/advance_math.dart';
LOGARITHM

Logarithm

Base-10 logarithm of a number is also implemented.

print(log10(100));  // Output: 2.0

Compute the natural logarithm of of a number using the function below. It also supports computes logarithm to any base.

// Natural log of `e`
print(log(math.e));  // Output: 1.0

//log to any base. Example log to base 10 on 100
print(log(100, 10)); // prints: 2.0

Compute the logarithm of a number to a given base.

print(logBase(10, 100));  // Output: 2.0
print(logBase(2, 8));  // Output: 3.0
print(logBase(2, 32));  // Output: 5.0
CODE TRANSLATOR

Morse Code

This library provides a class, MorseCode, for encoding and decoding messages using the Morse code system. It offers custom delimiters for characters, words, and new lines in Morse code. The class also includes a rate limiter to prevent abuse of the encode/decode functions and optional logging for debugging purposes.

main(){
  // Create an instance of morse code translator
  var translator = MorseCode();

  // Convert words to morse code
  var encoded = translator.encode('SOS');
  print('Encoded: $encoded'); // Encoded: ... --- ...
  print('');

  // Convert the morse code to words
  var decoded = translator.decode(encoded);
  print('Decoded: $decoded'); // Decoded: SOS
}

Rate Limiting and Logging

The MorseCodeTranslator class includes a rate limiter to prevent abuse of the encode/decode functions. You can enable or disable logging by setting the loggingEnabled flag to true or false. When logging is enabled, informational messages will be logged to the console.

Caching

To improve efficiency, the translator caches previously decoded Morse code strings. This allows for faster decoding of repeated messages without having to recompute them.

void main() {
  // Create an instance of rate limiter
  var rateLimiter = RateLimiter(
    maxRequests: 10,
    interval: Duration(seconds: 10),
  );

  // An instance of morse code translator with logging enabled and rate limiter parsed
  var translator = MorseCode(
    loggingEnabled: true,
    rateLimiter: rateLimiter,
  );

  encoded = translator.encode('Enable logging for debugging');
  print('Encoded: $encoded');

  decoded = translator.decode(encoded);
  print('Decoded: $decoded');

  print('');
  print('Decoded directly');
  String decodingValue =
      ".... .. / - .... . .-. . / .... --- .-- / .- .-. . / -.-- --- ..- ..--..";
  decoded = translator.decode(decodingValue);
  print('Decoded: $decoded');
}

// Encoding input: Enable logging for debugging
// Encoded: . -. .- -... .-.. . / .-.. --- --. --. .. -. --. / ..-. --- .-. / -.. . -... ..- --. --. .. -. --.
// Decoded: ENABLE LOGGING FOR DEBUGGING
// 
// Decoded directly
// Decoded: HI THERE HOW ARE YOU?

NumOrWords

NumOrWords (Numbers or Words) is a Dart class designed to convert numerical values into their word representations and vice-versa. It is highly customizable, catering to multiple languages, currency representations, and more.

Features

  • Basic Number Conversion: Convert any number into its word representation.
  • Currency Representation: Represent numbers in their currency form (e.g., Dollars, Euros).
  • Decimal Precision: Define the precision for decimal numbers.
  • Ordinal Numbers: Convert numbers into their ordinal form (e.g., 1st, 2nd, 3rd).
  • Multiple Languages Support: Easily extendable for multiple languages.
  • Number Extension: Conveniently use the Dart extension on numbers for quick conversion.

Basic Usage

To begin, instantiate the NumOrWords class by providing language configurations.

var converter = NumOrWords(languages: {'en': englishConfig});

Converting a Number to Words

Simply call the convert method on the converter instance.

print(converter.toWords(45.6743));  // Forty-Five Point Six Seven Four Three

Defining Decimal Precision

You can also specify the precision for decimal numbers.

print(converter.toWords(45.6743, decimalPlaces: 10));  // Forty-Five Point Six Seven Four Three

Currency Representation

To represent numbers in their currency form, specify the currency.

print(converter.convert(45.6743, currency: usd));  // Forty-Five Dollars And Sixty-Seven Cents Only

Using the Number Extension

For convenience, the package also provides an extension on the number type.

print(45.67.toWords(currency: usd));  // Forty-Five Dollars And Sixty-Seven Cents Only

Advanced Number Conversions

The package can handle a variety of number forms and scenarios.

print(converter.toWords(0));  // Zero
print(converter.toWords(1));  // One
print(converter.toWords(10));  // Ten
print(converter.toWords(100));  // One Hundred
print(converter.toWords(101));  // One Hundred And One
print(converter.toWords(111));  // One Hundred And Eleven

Ordinal Numbers

To convert numbers into their ordinal form, use the useOrdinal parameter.

print(converter.toWords(111, useOrdinal: true));  // One Hundred And Eleventh
print(converter.toWords(13, useOrdinal: true));  // Thirteenth
print(converter.toWords(21, useOrdinal: true));  // Twenty-First
print(converter.toWords(30, useOrdinal: true));  // Thirtieth
print(converter.toWords(40, useOrdinal: true));  // Fortieth

Words to Numver

The supports only French and English for the mean time. You can convert number to either English or French and back to number with losing precision.

  void displayConversion(NumOrWords converter, num value,
      {String lang = 'en',
      int decimalPlaces = 2,
      bool useOrdinal = false,
      bool isFeminine = false,
      Currency? currency}) {
    var result = converter.toWords(value,
        lang: lang,
        decimalPlaces: decimalPlaces,
        useOrdinal: useOrdinal,
        isFeminine: isFeminine,
        currency: currency);
    print(result);
    print(converter.toNum(result, lang: lang, currency: currency));
    print('---');
  }

  var converter = NumOrWords();

  print('--- French ---');
  displayConversion(converter, 301, lang: 'fr', useOrdinal: true);
  displayConversion(converter, 123, lang: 'fr', decimalPlaces: 10);
  displayConversion(converter, 6743, lang: 'fr', decimalPlaces: 10);
  displayConversion(converter, 123.6743, lang: 'fr', decimalPlaces: 10);
  displayConversion(converter, 123.6743, lang: 'fr', currency: cefaCurrency);
  displayConversion(converter, 84656789, lang: 'fr');
  displayConversion(converter, 9181601, lang: 'fr');
  displayConversion(converter, 8666529123484656789, lang: 'fr');

  print('\n--- English ---');
  displayConversion(converter, 301, lang: 'en', useOrdinal: true);
  displayConversion(converter, 123, lang: 'en', decimalPlaces: 10);
  displayConversion(converter, 6743, lang: 'en', decimalPlaces: 10);
  displayConversion(converter, 123.6743, lang: 'en', decimalPlaces: 10);
  displayConversion(converter, 123.6743, lang: 'en', currency: usdCurrency);
  displayConversion(converter, 9181601, lang: 'en');
  displayConversion(converter, 8666529123484656789, lang: 'en');


// --- French ---
// Trois Cents-et-Un
// 301
// ---
// Cent et Vingt-et-Trois
// 123
// ---
// Six Mille Sept Cents et Quarante-et-Trois
// 6743
// ---
// Cent et Vingt-et-Trois Point Six Mille Sept Cents et Quarante-et-Trois
// 123.6743
// ---
// Cent et Vingt-et-Trois Francs et Soixante-et-Sept Centimes Seulement
// 123.67
// ---
// Quatre-Vingt-et-Quatre Million Six Cents et Cinquante-et-Six Mille Sept Cents et Quatre-Vingt-et-Neuf
// 84656789
// ---
// Neuf Million Cent et Quatre-Vingt-et-Un Mille Six Cents et Un
// 9181601
// ---
// Huit Trillion Six Cents et Soixante-et-Six Billiard Cinq Cents et Vingt-et-Neuf Billion Cent et Vingt-et-Trois Milliard Quatre Cents et Quatre-Vingt-et-Quatre Million Six Cents et Cinquante-et-Six Mille Sept Cents et Quatre-Vingt-et-Neuf
// 8666529123484656789
// ---
//
// --- English ---
// Three Hundred And First
// 301
// ---
// One Hundred And Twenty-Three
// 123
// ---
// Six Thousand Seven Hundred And Forty-Three
// 6743
// ---
// One Hundred And Twenty-Three Point Six Thousand Seven Hundred And Forty-Three
// 123.6743
// ---
// One Hundred And Twenty-Three Dollars And Sixty-Seven Cents Only
// 123.67
// ---
// Nine Million One Hundred And Eighty-One Thousand Six Hundred And One
// 9181601
// ---
// Eight Quintillion Six Hundred And Sixty-Six Quadrillion Five Hundred And Twenty-Nine Trillion One Hundred And Twenty-Three Billion Four Hundred And Eighty-Four Million Six Hundred And Fifty-Six Thousand Seven Hundred And Eighty-Nine
// 8666529123484656789
// ---

LanguageConfig and Currency Configurations

The LanguageConfig and Currency classes are central to the NumOrWords package. They allow for deep customization and extensibility to cater to different languages and currency formats.

Currency Configuration

For currency representation, you can define the singular and plural forms of both main and fractional units using the Currency class.

These configurations (Currency and LanguageConfig) form the backbone of the NumOrWords package. By leveraging their flexibility, users can accurately convert numbers to word representations for a vast range of languages and currency formats. Whether you're targeting a single language or a global audience, NumOrWords ensures precision and extensibility.

Example:

final Currency usd = Currency.inUnits(
  1.0,
  CurrencyUnits(
    'United States Dollars',
    '\$',
    'USD',
    null,
    1.0,
    false,
  mainUnitSingular: 'Dollar',
  mainUnitPlural: 'Dollars',
  fractionalUnitSingular: 'Cent',
  fractionalUnitPlural: 'Cents',
  ),
);

In the above example, the Currency configuration is set for US Dollars, with "Dollar" as the singular form, "Dollars" as the plural, "Cent" as the fractional singular, and "Cents" as the fractional plural.

LanguageConfig

The LanguageConfig class provides a comprehensive configuration for number-word conversion in a specific language. It defines the word representations for different number sections, such as ones, tens, hundreds, magnitudes, etc., and also handles special conditions like ordinals.

Example:

/// An English configuration for conversion
final LanguageConfig englishConfig = LanguageConfig(
  ones: {
    '0': "Zero",
    '1': "One",
    '2': "Two",
    '3': "Three",
    '4': "Four",
    '5': "Five",
    '6': "Six",
    '7': "Seven",
    '8': "Eight",
    '9': "Nine"
  },
  teens: {
    '10': "Ten",
    '11': "Eleven",
    '12': "Twelve",
    '13': "Thirteen",
    '14': "Fourteen",
    '15': "Fifteen",
    '16': "Sixteen",
    '17': "Seventeen",
    '18': "Eighteen",
    '19': "Nineteen"
  },
  tens: {
    '2': "Twenty",
    '3': "Thirty",
    '4': "Forty",
    '5': "Fifty",
    '6': "Sixty",
    '7': "Seventy",
    '8': "Eighty",
    '9': "Ninety"
  },
  hundreds: {
    '1': "One Hundred",
    '2': "Two Hundred",
    '3': "Three Hundred",
    '4': "Four Hundred",
    '5': "Five Hundred",
    '6': "Six Hundred",
    '7': "Seven Hundred",
    '8': "Eight Hundred",
    '9': "Nine Hundred"
  },
  magnitudes: [
    "",
    "Thousand",
    "Million",
    "Billion",
    "Trillion",
    "Quadrillion",
    "Quintillion",
    "Sextillion",
    "Septillion",
    "Octillion",
    "Nonillion",
    "Decillion",
    "Undecillion",
    "Duodecillion",
    "Tredecillion",
    "Quattuordecillion",
    "Quindecillion",
    "Sexdecillion",
    "Septendecillion",
    "Octodecillion",
    "Novemdecillion",
    "Vigintillion"
  ],
  fractionalSeparator: 'Point',
  negativeTerm: 'Negative',
  currencySuffix: 'Only',
  tensDelimiter: "-",
  ordinalSuffixes: {1: "st", 2: "nd", 3: "rd", -1: "th"},
  ordinalFunction: (value, {bool isFeminine = false}) {
    // Helper function to get the ordinal for numbers from 1 to 19
    String simpleOrdinal(int num) {
      if (num == 1) return 'First';
      if (num == 2) return 'Second';
      if (num == 3) return 'Third';
      if (num == 4) return 'Fourth';
      if (num == 5) return 'Fifth';
      if (num == 6) return 'Sixth';
      if (num == 7) return 'Seventh';
      if (num == 8) return 'Eighth';
      if (num == 9) return 'Ninth';
      if (num == 12) return 'Twelfth';

      return "${englishConfig.convertChunk(num)}${englishConfig.ordinalSuffixes[-1]!}";
    }

    String twoDigitOrdinal(int num) {
      if (num >= 10 && num < 20) {
        // Special cases for 11th to 19th
        return englishConfig.teens["$num"]! +
            englishConfig.ordinalSuffixes[-1]!;
      }
      if (num >= 20) {
        int tensPart = num ~/ 10;
        int onesPart = num % 10;
        var v = englishConfig.tens["$tensPart"]!;
        if (onesPart == 0) {
          return "${v.substring(0, v.length - 1)}ieth";
        } else {
          return "$v-${simpleOrdinal(onesPart)}";
        }
      }
      return simpleOrdinal(num);
    }

    if (value < 100) {
      return twoDigitOrdinal(value);
    }

    String cardinal = englishConfig.convertChunk(value);
    List<String> parts = cardinal.split(' ');

    // For numbers above 99, replace only the last part with its ordinal
    String lastPartOrdinal = twoDigitOrdinal(value % 100);
    parts[parts.length - 1] = lastPartOrdinal;

    return parts.join(' ');
  },
  reverseOrdinalFunction: (value) {
    value = value.replaceFirst('First', 'One');
    value = value.replaceFirst('Second', 'Two');
    value = value.replaceFirst('Third', 'Three');
    value = value.replaceFirst('Fourth', 'Four');
    value = value.replaceFirst('Fifth', 'Five');
    value = value.replaceFirst('Sixth', 'Six');
    value = value.replaceFirst('Seventh', 'Seven');
    value = value.replaceFirst('Eighth', 'Eight');
    value = value.replaceFirst('Ninth', 'Nine');
    value = value.replaceFirst('Twelfth', 'Twelve');

    // Split the input into words
    List<String> words = value.split(RegExp(r'[\s\-]'));

    if (words.last.endsWith('ieth')) {
      value = value.replaceFirst(
          words.last, '${words.last.substring(0, words.last.length - 4)}y');
    } else if (words.last.endsWith('th')) {
      value = value.replaceFirst(
          words.last, words.last.substring(0, words.last.length - 2));
    }

    return value;
  },
  chunkConversionRule: (num currentValue, String word, LanguageConfig config) {
    if (word == "Hundred") {
      return currentValue == 0 ? 100 : currentValue * 100;
    } else if (config.magnitudes.contains(word)) {
      num magnitudeValue = pow(10, config.magnitudes.indexOf(word) * 3);
      return currentValue * magnitudeValue;
    }

    return 0; // Default case, can be adjusted as needed
  },
  defaultConjunction: "And",
  unitsBeforeTens: false,
);

In the provided example, the LanguageConfig is set for English. It specifies the words for ones, tens, hundreds, etc., and also handles the logic for ordinals. The configuration also includes details like the word for negative numbers (Negative), currency suffix (Only), and the delimiter used between tens and ones (-).

Extending for Multiple Languages

To support multiple languages, simply extend the LanguageConfig for each language and provide it to the NumOrWords class.

Conclusion

NumOrWords offers a comprehensive solution for converting numbers into words, supporting a wide range of use-cases and customization. Whether you need simple word representation or complex multi-language support with currency, NumOrWords has got you covered.

ZScore

ZScore

Computes Z-scores based on a given confidence level. The class provides functionalities to compute Z-scores, which are used in statistical hypothesis testing.

The Z-score represents how many standard deviations an element is from the mean.

var confidenceLevels = [
    10,
    20,
    30,
    40,
    50,
    60,
    70,
    80,
    85,
    90,
    95,
    99.0,
    99.999,
    99.99999,
    99.9999999
  ];
  for (var cl in confidenceLevels) {
    double zScore = ZScore.computeZScore(cl);
    print("Z-score for $cl% confidence level is $zScore");
  }

// Z-score for 10% confidence level is 0.12538099310291884
// Z-score for 20% confidence level is 0.25293326782658254
// Z-score for 30% confidence level is 0.3848770849965131
// Z-score for 40% confidence level is 0.5240018703826799
// Z-score for 50% confidence level is 0.6741891400433162
// Z-score for 60% confidence level is 0.8414567173547839
// Z-score for 70% confidence level is 1.0364314851895606
// Z-score for 80% confidence level is 1.281728756502709
// Z-score for 85% confidence level is 1.4398004696260025
// Z-score for 90% confidence level is 1.645211440143815
// Z-score for 95% confidence level is 1.9603949169253396
// Z-score for 99.0% confidence level is 2.5762360813095704
// Z-score for 99.999% confidence level is 4.417087697546128
// Z-score for 99.99999% confidence level is 5.326446072058037
// Z-score for 99.9999999% confidence level is 6.109029815669355

Compute the confidence level using the Z-Scroe value

print(ZScore.computeConfidenceLevel(1.9603949169253396)); // 95.00503548449109
print(ZScore.computeConfidenceLevel(5.326446072058037)); // 99.99998998470075

Confidence interval around a sample mean, you generally need the sample mean (x), the sample size (n), and the standard deviation (σ) or the standard error of the sample mean (SE). The Z-score corresponding to the desired confidence level is also required.

var interval = ZScore.computeConfidenceInterval(50, 100, 10, 95);
print("Confidence Interval: (${interval.lower}, ${interval.upper})");
// Output: Confidence Interval: (48.040605084588995, 51.959394915411005)

Compute the Probability Density Function (PDF) and Cumulative Density Function (CDF) for a standard normal distribution to the ZScore class.

print(ZScore.computeCDF(0)); // 0.49999998499999976
print(ZScore.computePDF(0)); // 0.3989422804014327

other computational functions includes:

// Compute p-value from a given Z-score.
print(ZScore.computePValue(1.96)); // 0.025

// Convert Z-score to T-score.
print(ZScore.convertZToT(1.96)); // 69.6

// Compute the percentile from a given Z-score.
print(ZScore.computePercentile(1.96)); // 97.5

// Compute Z-score from a raw score.
print(ZScore.computeZScoreFromRawScore(110, 100, 15)); // 0.6666666666666666
ANGLE

Angle Class

The Angle class is part of the advanced_math library. It's designed to make working with angles straightforward in a variety of units, including degrees, radians, gradians, and DMS (Degrees, Minutes, Seconds).

Features

  1. Create an Angle object with any of the four units. The class will automatically convert it to all other units and store them as properties:
var angleDeg = Angle.degrees(45);
var angleRad = Angle.radians(math.pi / 4);
var angleGrad = Angle.gradians(50);
var angleDMS = Angle.dms([45, 0, 0]);
  1. Get the smallest difference between two angles:
num diff = angleDeg.smallestDifference(angleRad);
  1. Interpolate between two angles:
Angle interpolated = angleDeg.interpolate(angleRad, 0.5);
  1. Convert an angle from one unit to another:
double rad = Angle.convert(180, AngleType.degrees, AngleType.radians);  // Converts 180 degrees to radians
print(rad);  // Outputs: 3.141592653589793

double grad = Angle.convert(1, AngleType.radians, AngleType.gradians);  // Converts 1 radian to gradians
print(grad);  // Outputs: 63.661977236758134
  1. Convert degrees to gradians, radians, minutes or seconds, and vice versa:
double minutes = degrees2Minutes(1);  // Output: 60.0
double degreesFromMinutes = minutes2Degrees(60);  // Output: 1.0
double seconds = degrees2Seconds(1);  // Output: 3600.0
double degreesFromSeconds = seconds2Degrees(3600);  // Output: 1.0
  1. Perform all the possible trignometry functions on the angle:
var angle = Angle.degrees(45);
var t1 = angle.sin();
var t2 = angle.cos();
var t3 = angle.tan();
var t4 = angle.tanh();
var t5 = angle.atanh();

These features provide an easy-to-use interface for handling various angle calculations, especially for applications that require geometric computations or work with geospatial data. The Angle class is an essential part of the advanced_math library and can be useful for anyone who needs advanced mathematical operations in Dart.

GEOMETRY

Geometry Library

This library provides a suite of classes and functions to work with geometric objects and perform geometric calculations.

Usage

Point

A Point represents a point in a 2D space.

Point p1 = Point(3, 4); // 2D point
print(p1.x); // prints: 3
print(p1.y); // prints: 4

var p2 = Point(1, 2, 3);  // 3D point
print(p2.is3DPoint) // true

var p = Point.fromPolarCoordinates(5, radians(53.13));
print(p); // Output: Point(3.0000000000000004, 3.9999999999999996)

var p = Point.fromSphericalCoordinates(5, radians(53.13), radians(30));
print(p); // Output: Point(1.50, 1.999997320371271, 4.330127018922194)

A Point3D represents a point in a 3D space.

Point3D p1 = Point3D(3, 4, 2); // 3D point
print(p1.x); // prints: 3
print(p1.y); // prints: 4

Compute Distances Example 1:

var p1 = Point(3, 4);
var p2 = Point(6, 8);
print(p1.distanceTo(p2)); // Output: 5.0

var point1 = Point(2, 3);
var point2 = Point(5, 11);
print(point1.slopeTo(point2)); // Output: 2.6666666666666665

Example 2:

var point1 = Point(1, 2, 3);
var point2 = Point(4, 5, 6);
print(point1.distanceTo(point2)); // Output: 5.196152422706632
print(point1.midpointTo(point2)); // Output: Point(2.5, 3.5, 4.5)

Arithmetics of points

var point1 = Point(2, 2);
var point2 = Point(1, 1);
print(point1 - point2); // Output: Point(1.0, 1.0)
print(point1 + point2); // Output: Point(3.0, 3.0)
print(point1 * 2); // Output: Point(4.0, 4.0)
print(point1 / 2); // Output: Point(1.0, 1.0)

Others include: bearingTo, distanceToLine, isCollinear etc

var point = Point(2, 0);
var origin = Point(1, 0);
Angle angle = Angle.radians(math.pi / 2)
var rotated = point.rotateBy(angle, origin)
print(rotated); // Output: Point(1, 1)

var point = Point(1, 2, 3);
print(point.move(1, -1, 2)); // Output: Point(2, 1, 5)
print(point.scale(2)); // Output: Point(2, 4, 6)
print(point.reflect(Point(0, 0, 0))); // Output: Point(-1, -2, -3)

Line

A Line represents a line in a 2D space, defined by two points.

var line1 = Line(p1: Point(1, 1), p2: Point(2, 2));
print(line1); // Output: Line(Point(1.0, 1.0), Point(2.0, 2.0))

var line2 = Line(gradient: 1, intercept: 0);
print(line2); // Output: Line(Point(0.0, 0.0), Point(1.0, 1.0))

var line3 = Line(gradient: 2.0, intercept: 2.0, x: 3.0);
print(line3); // Output: Line(Point(3.0, 8.0), Point(4.0, 10.0))

var line4 = Line(y: 1.0, gradient: 2.0, intercept: 3.0);
print(line4); // Output: Line(Point(-1.0, 1.0), Point(0.0, 3.0))

var line5 = Line(y: 1.0, gradient: -0.5, intercept: 7.0);
print(line5); // Output: Line(Point(-12.0, 1.0), Point(-11.0, 5.5))

var line6 = Line(y: 1.0, gradient: 2.0, x: 1.0);
print(line6); // Output: Line(Point(1.0, 1.0), Point(2.0, 3.0))

Plane

A class that represents a plane in a three-dimensional space. Each instance of this class is defined by a [Point] and a normal [Vector].

var point = Point(1, 2, 3);
var normal = Vector(1, 0, 0);
var plane = Plane(point, normal);
print(plane);  // Output: Plane(point: Point(1, 2, 3), normal: Vector(1, 0, 0))
var pivot = Point(2, 3, 4);
var perpendicularLine = plane.perpendicularLine(pivot);
print(perpendicularLine);  // Output: Plane(Point(2, 3, 4), Vector(1, 0, 0))
var otherPoint = Point(1, 3, 4);
var newPlane = plane.parallelThroughPoint(otherPoint);
print(newPlane);  // Output: Plane(point: Point(1, 3, 4), normal: Vector(1, 0, 0))

Circle

A Circle is represented by a center point and a radius.

var center = Point(0, 0);
var circle = Circle(center, 5);
print(circle.area()); // Output: 78.53981633974483
print(circle.circumference()); // Output: 31.41592653589793
print(circle.isPointInside(Point(3, 4))); // Output: true

Polygon

A Polygon is represented by a list of points. The points should be ordered either clockwise or counter-clockwise.

Point p1 = Point(0, 0);
Point p2 = Point(1, 0);
Point p3 = Point(0, 1);
Polygon triangle = Polygon([p1, p2, p3]);
print(triangle.area); // prints: 0.5

Other things you could do with polygon are area with different methods, compute lengths, scale, perimeter etc.

var vertices = [
  Point(1613.26, 2418.11),
  Point(1806.71, 2523.16),
  Point(1942.17, 2366.84),
  Point(1901.89, 2203.18),
  Point(1652.08, 2259.26)
];

var polygon = Polygon(vertices: vertices);
print(polygon);
print('');

print('Area:');
print("Shoelace formula: ${polygon.shoelace()}");
print("Triangulation: ${polygon.triangulation()}");
print("Trapezoidal rule: ${polygon.trapezoidal()}");
print("Monte Carlo method (10,000 points): ${polygon.monteCarlo()}");
print("Green's theorem: ${polygon.greensTheorem()}");

print("\nCentroid: ${polygon.centroid()}");
print("Moment of inertia: ${polygon.momentOfInertia()}");

print("\nAngle Between Side 1 and 2: ${polygon.angleBetweenSides(0, 1)}");
print("Length of side 1: ${polygon.sideLengthIrregular(0)}");
print("Length of side 2: ${polygon.sideLengthIrregular(1)}");

print(
    "\nIs Point(1806.71, 2523.16) inside: ${polygon.isPointInsidePolygon(Point(1806.71, 2400.16))}");
print("Is convex: ${polygon.isConvex()}");

print("\nBounding box: ${polygon.boundingBox()}");

print("\nOriginal: ${polygon.vertices}");
polygon.scale(2.5);
print("\nScaled by 2.5: ${polygon.vertices}");

polygon.scale(1 / 2.5);
print("\nUnScale by 1/2.5: ${polygon.vertices}");

polygon.translate(1.0, 1.0);
print("\nTranslated by (1.0, 1.0): ${polygon.vertices}");

print(
    "\nNearest point on the polygon to (1920.17, 2200.18): ${polygon.nearestPointOnPolygon(Point(1920.17, 2200.18))}");

printLine('Regular Polygon');

var regPolygon = RegularPolygon(numSides: 5, sideLength: 4);

print("Area: ${regPolygon.areaPolygon()}");
print("Perimeter: ${regPolygon.perimeter()}");
print("Interior angle: ${regPolygon.interiorAngle()}");
print("Exterior angle: ${regPolygon.exteriorAngle()}\n\n");

var perimeter = regPolygon.perimeter();
var area = regPolygon.areaPolygon();
var circumradius = regPolygon.circumradius();
var inradius = regPolygon.inradius();

polygon = Polygon(numSides: regPolygon.numSides);

print(
    "Side length from perimeter: ${polygon.getSideLength(perimeter: perimeter)}");
print("Side length from area: ${polygon.getSideLength(area: area)}");
print(
    "Side length from circumradius: ${polygon.getSideLength(circumradius: circumradius)}");
print(
    "Side length from inradius: ${polygon.getSideLength(inradius: inradius)}");

Results:

Polygon( 
num_sides=5,
side_length=null,
vertices=[Point(1613.26, 2418.11), Point(1806.71, 2523.16), Point(1942.17, 2366.84), Point(1901.89, 2203.18), Point(1652.08, 2259.26)])

Area:
Shoelace formula: 68935.01805000007
Triangulation: 68935.01804999998
Trapezoidal rule: 68935.01805000001
Monte Carlo method (10,000 points): 69777.18425340003
Green's theorem: 68935.01805000007

Centroid: Point(1783.2220000000002, 2354.11)
Moment of inertia: 219478041763.1118

Angle Between Side 1 and 2: 1.313000433887411
Length of side 1: 220.13269861608467
Length of side 2: 206.84620857052207

Is Point(1806.71, 2523.16) inside: true
Is convex: true

Bounding box: [Point(1613.26, 2203.18), Point(1942.17, 2203.18), Point(1942.17, 2523.16), Point(1613.26, 2523.16)]

Original: [Point(1613.26, 2418.11), Point(1806.71, 2523.16), Point(1942.17, 2366.84), Point(1901.89, 2203.18), Point(1652.08, 2259.26)]

Scaled by 2.5: [Point(4033.15, 6045.275000000001), Point(4516.775, 6307.9), Point(4855.425, 5917.1), Point(4754.725, 5507.95), Point(4130.2, 5648.150000000001)]

UnScale by 1/2.5: [Point(1613.2600000000002, 2418.11), Point(1806.71, 2523.16), Point(1942.17, 2366.84), Point(1901.8900000000003, 2203.18), Point(1652.08, 2259.26)]

Translated by (1.0, 1.0): [Point(1614.2600000000002, 2419.11), Point(1807.71, 2524.16), Point(1943.17, 2367.84), Point(1902.8900000000003, 2204.18), Point(1653.08, 2260.26)]

Nearest point on the polygon to (1920.17, 2200.18): Point(1920.17, 2200.18)

--- --- --- --- --- --- --- --- --- --- Regular Polygon --- --- --- --- --- --- --- --- --- --- 

Area: 27.52763840942347
Perimeter: 20.0
Interior angle: 108.0
Exterior angle: 72.0


Side length from perimeter: 4.0
Side length from area: 4.0
Side length from circumradius: 4.0
Side length from inradius: 4.0

Triangle

A Triangle is a special kind of polygon. It can be created by providing the lengths of its sides, or its coordinates.

Triangle triangle1 = Triangle(a: 3, b: 4, c: 5);
print(triangle1.area(AreaMethod.heron)); // prints: 6.0

Triangle triangle2 = Triangle(A: Point(0, 0), B: Point(3, 0), C: Point(0, 4));
print(triangle2.area(AreaMethod.coordinates)); // prints: 6.0

SphericalTriangle

A SphericalTriangle is a triangle on the surface of a sphere. It can be created by providing the lengths of its sides and the radius of the sphere.

  var triangle = SphericalTriangle.fromAllSides( Angle(rad: pi / 2), Angle(rad: pi / 3), Angle(rad: pi / 4));

  // Angles
  print('AngleA: ${triangle.angleA} '); // AngleA: Angle: 35.26438968275524° or 0.6154797086703871 rad or [35, 15, 51.802857918852396]
  print('AngleB: ${triangle.angleB} '); // AngleB: Angle: 125.26438968275677° or 2.186276035465284 rad or [125, 15, 51.80285792437758]
  print('AngleC: ${triangle.angleC}'); // AngleC: Angle: 45.00000000000074° or 0.785398163397448 rad or [45, 0, 2.660272002685815e-9]

  // Sides
  print('SideA: ${triangle.sideA}'); // SideA: Angle: 90.00000000000152° or 1.5707963267948966 rad or [90, 0, 5.474021236295812e-9]
  print('SideB: ${triangle.sideB}'); // SideB: Angle: 60.00000000000101° or 1.0471975511965976 rad or [60, 0, 3.632294465205632e-9]
  print('SideC: ${triangle.sideC} '); // SideC: Angle: 45.00000000000076° or 0.7853981633974483 rad or [45, 0, 2.737010618147906e-9]

  print('Area: ${triangle.area} ≈ ${triangle.areaPercentage} % of unit sphere surface area'); // Area: 0.445561253943326 ≈ 3.545663800765179 % of unit sphere surface area
  print('Perimeter: ${triangle.perimeter} ≈ ${triangle.perimeterPercentage} % of unit sphere circumference'); // Perimeter: 3.4033920413889422 ≈ 54.166666666666664 % of unit sphere circumference
  print('isValidTriangle: ${triangle.isValidTriangle()}'); // isValidTriangle: true
POLYNOMIALS

Polynomials

The Geometry Library provides comprehensive support for Polynomials. This includes polynomials of different degrees, from linear to quartic, as well as a general polynomial implementation using the Durand-Kerner method for degrees of 5 or higher.

Usage

Linear

Linear polynomials are of the form ax + b = 0.

Linear linear = Linear.num(a: 2, b: -3);
print(linear.roots()); // Output: [1.5]

Quadratic

Quadratic polynomials are of the form ax² + bx + c = 0.

Quadratic quad = Quadratic.num(a: 2, b: -3, c: -2);
print(quad.roots()); // Output: [2.0, -0.5]
print(quad.vertex()); // Output: [0.75, -3.125]

Cubic

Cubic polynomials are of the form ax³ + bx² + cx + d = 0.

Cubic cubic = Cubic.num(a: -1, b: 1, c: 1, d: 2);
print(cubic.roots()); // Output: [-1.0, -1.0, 2.0]

Quartic

Quartic polynomials are of the form ax⁴ + bx³ + cx² + dx + e = 0.

Quartic quartic = Quartic.num(a: -1, b: -8, c: 0, d: 0, e: -1);
print(quartic.roots()); // Output: [1.0, -1.0, -1.0, -1.0]

Durand-Kerner

This is a general polynomial implementation that uses the Durand-Kerner method to find the roots of a polynomial with a degree of 5 or higher.

DurandKerner dk = DurandKerner.num([1, 5, 1, 4, 0, 3, 2]);
print(dk.degree); // 6
print(dk); // x⁶ + 5x⁵ + x⁴ + 4x³ + 3x + 2
print(dk.roots()); 
// [-0.34289017575006814 + 0.9530107213799093i, -0.34289017581899034 - 0.9530107213040406i, 0.5696766117867249 + 0.6923844884012686i, -4.9651242864231895, 0.5696766117855657 - 0.6923844884824355i, -0.4884485856011231]

Additional Features

Each of these polynomials can be differentiated, integrated, simplified, and evaluated.

Polynomial poly = Polynomial.fromList([3, -6, 12]);
print(poly); // 3x² - 6x + 12
print(poly.simplify()); // x² - 2x + 4
print(poly.roots()); // [1 + 1.7320508075688774i, 1 - 1.7320508075688774i]
print(poly.differentiate()); // 6x - 6
print(poly.integrate()); // x³ - 3x² + 12x
print(poly.evaluate(2)); // 12.0
Polynomial p = Polynomial.fromString("x^5 - x^4 - x + 1");
print(p.coefficients); // [1.0, -1.0, 0, 0, -1.0, 1.0]
print(p); // x⁵ - x⁴ - x + 1.0
print(p.evaluate(Complex(-19 / 8, 7.119033245839726e-16))); // -104.00619506835938
print(p.roots());
// [2.481185557213347e-11 - 0.9999999999737949i, -1.0000000000550548 + 3.5929979905099436e-11i, 1.0000004031257346 + 2.7703711854406305e-7i, 5.095265802549413e-11 + 1.0000000000706935i, 1.0000004031257346 + 2.7703711854406305e-7i]
print('');
ROMAN NUMERALS

Roman Numerals

A Dart class designed to provide efficient conversions between Roman numerals and integers. This class also supports arithmetic operations directly on Roman numeral representations.

Features

  • Convert integers to Roman numerals and vice versa.
  • Supports numbers up to 3,999 using standard Roman numerals.
  • Supports numbers above 3,999 using parentheses notation.
  • Provides arithmetic operations on Roman numerals.
  • Caches recent conversions for performance.

Usage

Instantiation

RomanNumerals romanFive = RomanNumerals(5); 
print(romanFive) // V
print(RomanNumerals(69)); // LXIX
print(RomanNumerals(8785)); // (VIII)DCCLXXXV

Conversion from Roman to Integer

RomanNumerals romanYear = RomanNumerals.fromRoman("MMXXIII");
print(romanYear.value);  // Outputs: 2023
print(RomanNumerals.fromRoman('(VIII)DCCLXXXV').value); // 8785

Arithmetic Operations

RomanNumerals a = RomanNumerals.fromRoman('MMXXIII'); // 2023
RomanNumerals b = RomanNumerals.fromRoman('X'); // 10

print(a + b); // MMXXXIII
print(a - b); // MMXIII
print(a * b); // (XX)CCXXX
print(a / b); // CCII
print(a % b); // III

print(RomanNumerals.fromRoman('MXXII') - RomanNumerals.fromRoman('LXX') - RomanNumerals.fromRoman('LII')); // CM
print(RomanNumerals.fromRoman('(M)') - RomanNumerals.fromRoman('(CC)DXXV')); // (DCCXCIX)CDLXXV
print(RomanNumerals.fromRoman('(DCCXCIX)CDLXXV').value); // 799475

Also support shifting the bits of this integer to the left by [shiftAmount].

print(a << 1); // (IV)XLVI
print(RomanNumerals.fromRoman('(IV)XLVI').value);
print((a >> 1).value); // 1011

Logical, Comparison Operations

RomanNumerals a = RomanNumerals.fromRoman('MMXXIII'); // 2023
RomanNumerals b = RomanNumerals.fromRoman('X'); // 10

print(a & b); // II (bitwise AND)
print(a | b); // MMXXXI (bitwise OR)
print(a ^ b); // MMXXIX (bitwise XOR)
print(a == b); // false
print(a > b); // true
print(a < b); // false
print(a >= b); // true
print(a <= b); // false

Date to and from Roman numerals

  print(RomanNumerals.dateToRoman('August 22, 1989', format: 'MMMM d, y', sep: '・')); // Outputs: VIII・XXII・MCMLXXXIX
  print(RomanNumerals.dateToRoman('Dec-23, 2017', format: 'MMM-d, y')); // Outputs: XII • XXIII • MMXVII
  print(RomanNumerals.dateToRoman('Jul-21, 2016', format: 'MMM-d, y')); // Outputs: VII • XXI • MMXVI

  print(RomanNumerals.romanToDate('VIII・XXII・MCMLXXXIX', format: 'MMMM d, y', sep: '・')); // Outputs: August 22, 1989
MATRIX

Matrix

Create a Matrix

You can create a Matrix object in different ways:

Create a 2x2 Matrix from string

Matrix a = Matrix("1 2 3; 4 5 6; 7 8 9");
print(a);
// Output:
// Matrix: 3x3
// ┌ 1 2 3 ┐
// │ 4 5 6 │
// └ 7 8 9 ┘

Create a matrix from a list of lists

Matrix b = Matrix([[1, 2], [3, 4]]);
print(b);
// Output:
// Matrix: 2x2
// ┌ 1 2 ┐
// └ 3 4 ┘

Create a matrix from a list of diagonal objects

Matrix d = Matrix.fromDiagonal([1, 2, 3]);
print(d);
// Output:
// Matrix: 3x3
// ┌ 1 0 0 ┐
// │ 0 2 0 │
// └ 0 0 3 ┘

Create a matrix from a flattened array

final source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
final ma = Matrix.fromFlattenedList(source, 2, 6);
print(ma);
// Output:
// Matrix: 2x6
// ┌ 1 2 3 4 5 6 ┐
// └ 7 8 9 0 0 0 ┘

Create a matrix from list of columns

var col1 = ColumnMatrix([1, 2, 3]);
var col2 = ColumnMatrix([4, 5, 6]);
var col3 = ColumnMatrix([7, 8, 9]);
var matrix = Matrix.fromColumns([col1, col2, col3]);
print(matrix);
// Output:
// Matrix: 3x3
// ┌ 1 4 7 ┐
// | 2 5 8 |
// └ 3 6 9 ┘

Create a matrix from list of rows

var row1 = RowMatrix([1, 2, 3]);
var row2 = RowMatrix([4, 5, 6]);
var row3 = RowMatrix([7, 8, 9]);
var matrix = Matrix.fromRows([row1, row2, row3]);
print(matrix);
// Output:
// Matrix: 3x3
// ┌ 1 2 3 ┐
// | 4 5 6 |
// └ 7 8 9 ┘

Create a from a list of lists

Matrix c = [[1, '2', true],[3, '4', false]].toMatrix()
print(c);
// Output:
// Matrix: 2x3
// ┌ 1 2  true ┐
// └ 3 4 false ┘

Create a 2x2 matrix with all zeros

Matrix zeros = Matrix.zeros(2, 2);
print(zeros)
// Output:
// Matrix: 2x2
// ┌ 0 0 ┐
// └ 0 0 ┘

Create a 2x3 matrix with all ones

Matrix ones = Matrix.ones(2, 3);
print(ones)
// Output:
// Matrix: 2x3
// ┌ 1 1 1 ┐
// └ 1 1 1 ┘

Create a 2x2 identity matrix

Matrix identity = Matrix.eye(2);
print(identity)
// Output:
// Matrix: 2x2
// ┌ 1 0 ┐
// └ 0 1 ┘

Create a matrix that is filled with same object

Matrix e = Matrix.fill(2, 3, 7);
print(e);
// Output:
// Matrix: 2x3
// ┌ 7 7 7 ┐
// └ 7 7 7 ┘

Create a matrix from linspace and create a diagonal matrix

Matrix f = Matrix.linspace(0, 10, 3);
print(f);
// Output:
// Matrix: 1x3
// [ 0.0 5.0 10.0 ]

Create from a range or arrange at a step

var m = Matrix.range(6, start: 1, step: 2, isColumn: false);
print(m);
// Output:
// Matrix: 1x3
// [ 1  3  5 ]

Create a random matrix within arange of values

var randomMatrix = Matrix.random(3, 4, min: 1, max: 10, isDouble: true);
print(randomMatrix);
// Output:
// Matrix: 3x4
// ┌ 3  5  9  2 ┐
// │ 1  7  6  8 │
// └ 4  9  1  3 ┘

Create a specific random matrix from the matrix factory

var randomMatrix = Matrix.factory
  .create(MatrixType.general, 5, 4, min: 0, max: 3, isDouble: true);
print('\n${randomMatrix.round(3)}');

Create a specific type of matrix from a random seed with range

randMat = Matrix.factory.create(MatrixType.general, 5, 4,
    min: 0, max: 3, seed: 12, isDouble: true);
print('\n${randMat.round(3)}');

// Output:
// Matrix: 5x4
// ┌ 1.949 1.388 2.833 1.723 ┐
// │ 0.121 1.954 2.386 2.407 │
// │ 2.758  2.81 1.026 0.737 │
// │ 1.951  0.37 0.075 0.069 │
// └ 2.274 1.932 2.659 0.196 ┘
var randomMatrix = Matrix.factory
    .create(MatrixType.sparse, 5, 5, min: 0, max: 2, seed: 12, isDouble: true);

print('\nProperties of the Matrix:\n${randomMatrix.round(3)}\n');
randomMatrix.matrixProperties().forEach((element) => print(' - $element'));

// Properties of the Matrix:
// Matrix: 5x5
// ┌ 0.0 1.149   0.0 0.0   0.0 ┐
// │ 0.0   0.0 0.925 0.0 1.302 │
// │ 0.0   0.0   0.0 0.0   0.0 │
// │ 0.0   0.0   0.0 0.0   0.0 │
// └ 0.0   0.0   0.0 0.0   0.0 ┘
//
//  - Square Matrix
//  - Upper Triangular Matrix
//  - Singular Matrix
//  - Vandermonde Matrix
//  - Nilpotent Matrix
//  - Sparse Matrix

Check Matrix Properties

Easy much easier to query the properties of a matrix.

var A = Matrix([
    [4, 1, -1],
    [1, 4, -1],
    [-1, -1, 4]
  ]);
print(A);

print('Shape: ${A.shape}');
print('Max: ${A.max()}');
print('Column Max: ${A.max(axis: 0)}');
print('Row Max: ${A.max(axis: 1)}');
print('Min: ${A.min()}');
print('Column Min: ${A.min(axis: 0)}');
print('Row Min: ${A.min(axis: 1)}');
print('Sum: ${A.sum()}');
print('Absolute Sum: ${A.sum(absolute: true)}');
print('Column Sum: ${A.sum(axis: 0)}');
print('Row Sum: ${A.sum(axis: 1)}');
print('Diagonal Sum: ${A.sum(axis: 2)}');
print('Diagonal Sum TLBR: ${A.sum(axis: 3)}');
print('Diagonal Sum TRBL: ${A.sum(axis: 4)}');
print('Mean: ${A.mean()}');
print('Median: ${A.median()}');
print('Product: ${A.product()}');
print('Variance: ${A.variance()}');
print('Standard Deviation: ${A.standardDeviation()}');
print('Absolute Sum: ${A.sum(absolute: true)}');
print('Determinant: ${A.determinant()}');
print('Rank: ${A.rank()}');
print('Trace: ${A.trace()}');
print('Skewness: ${A.skewness()}');
print('Kurtosis: ${A.kurtosis()}');
print('Condition number: ${A.conditionNumber()}');
print('Decomposition Condition number: ${A.decomposition.conditionNumber()}');

print('Manhattan Norm(l1Norm): ${A.norm(Norm.manhattan)}');
print('Frobenius/Euclidean Norm(l2Norm): ${A.norm(Norm.frobenius)}');
print('Chebyshev/Infinity Norm: ${A.norm(Norm.chebyshev)}');
print('Spectral Norm: ${A.norm(Norm.spectral)}');
print('Trace/Nuclear Norm: ${A.norm(Norm.trace)}');
print('Nullity: ${A.nullity()}');

print('Normalize: ${A.normalize()}\n');
print('Frobenius/Euclidean Normalize: ${A.normalize(Norm.frobenius)}\n');
print('Row Echelon Form: ${A.rowEchelonForm()}\n');
print('Reduced Row Echelon Form: ${A.reducedRowEchelonForm()}\n');
print('Null Space: ${A.nullSpace()}\n');
print('Row Space: ${A.rowSpace()}\n');
print('Column Space: ${A.columnSpace()}\n');
print('Matrix Properties:');
A.matrixProperties().forEach((element) => print(' - $element'));

// Output:
// Matrix: 3x3
// ┌  4  1 -1 ┐
// │  1  4 -1 │
// └ -1 -1  4 ┘
//
// Shape: [3, 3]
// Max: 4
// Column Max: [4, 4, 4]
// Row Max: [4, 4, 4]
// Min: -1
// Column Min: [-1, -1, -1]
// Row Min: [-1, -1, -1]
// Sum: 10
// Absolute Sum: 18
// Column Sum: [4, 4, 2]
// Row Sum: [4, 4, 2]
// Diagonal Sum: 12
// Diagonal Sum TLBR: [-1, 0, 12, 0, -1]
// Diagonal Sum TRBL: [4, 2, 2, -2, 4]
// Mean: 1.1111111111111112
// Median: 1
// Product: 64
// Variance: 4.765432098765432
// Standard Deviation: 2.1829869671542776
// Absolute Sum: 18
// Determinant: 54.0
// Rank: 3
// Trace: 12
// Skewness: 0.3705316948061136
// Kurtosis: -1.58891513866144
// Condition number: 3.6742346141747673
// Decomposition Condition number: 1.9999999999999998
// Manhattan Norm(l1Norm): 6.0
// Frobenius/Euclidean Norm(l2Norm): 7.3484692283495345
// Chebyshev/Infinity Norm: 6.0
// Spectral Norm: 5.999999999999999
// Trace/Nuclear Norm: 12.0
// Nullity: 0
// Normalize: Matrix: 3x3
// ┌   1.0  0.25 -0.25 ┐
// │  0.25   1.0 -0.25 │
// └ -0.25 -0.25   1.0 ┘

// Frobenius/Euclidean Normalize: Matrix: 3x3
// ┌   0.5443310539518174  0.13608276348795434 -0.13608276348795434 ┐
// │  0.13608276348795434   0.5443310539518174 -0.13608276348795434 │
// └ -0.13608276348795434 -0.13608276348795434   0.5443310539518174 ┘

// Row Echelon Form: Matrix: 3x3
// ┌ 1.0 0.25 -0.25 ┐
// │ 0.0  1.0  -0.2 │
// └ 0.0  0.0   1.0 ┘

// Reduced Row Echelon Form: Matrix: 3x3
// ┌ 1.0 0.0 0.0 ┐
// │ 0.0 1.0 0.0 │
// └ 0.0 0.0 1.0 ┘

// Null Space: Matrix: 0x0
// [ ]

// Row Space: Matrix: 3x3
// ┌  4  1 -1 ┐
// │  1  4 -1 │
// └ -1 -1  4 ┘
// Column Space: Matrix: 3x3
// ┌  4  1 -1 ┐
// │  1  4 -1 │
// └ -1 -1  4 ┘

// Matrix Properties:
//  - Square Matrix
//  - Full Rank Matrix
//  - Symmetric Matrix
//  - Non-Singular Matrix
//  - Positive Definite Matrix
//  - Diagonally Dominant Matrix
//  - Strictly Diagonally Dominant Matrix

Matrix Copy

Copy another original matrix

var a = Matrix();
a.copy(y); // Copy another matrix

Copy the elements of the another matrix and resize the current matrix

var matrixA = Matrix([[1, 2], [3, 4]]);
var matrixB = Matrix([[5, 6], [7, 8], [9, 10]]);
matrixA.copyFrom(matrixB, resize: true);
print(matrixA);
// Output:
// 5  6
// 7  8
// 9 10

Copy the elements of the another matrix but retain the current matrix size

var matrixA = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]);
var matrixB = Matrix([[10, 11], [12, 13]]);
matrixA.copyFrom(matrixB, retainSize: true);
print(matrixA);
// Output:
// 10 11 3
// 12 13 6
// 7  8  9

Matrix Interoperability

To convert a matrix to a json-serializable map one may use toJson method:

to<->from JSON

You can serialize the matrix to a json-serializable map and deserialize back to a matrix object.

final matrix = Matrix.fromList([
    [11.0, 12.0, 13.0, 14.0],
    [15.0, 16.0, 0.0, 18.0],
    [21.0, 22.0, -23.0, 24.0],
    [24.0, 32.0, 53.0, 74.0],
  ]);

// Convert to JSON representation
final serialized = matrix.toJson();

To restore a serialized matrix one may use Matrix.fromJson constructor:

final matrix = Matrix.fromJson(serialized);

to<->from CSV

You can write csv file and read it back to a matrix object.

String csv = '''
1.0,2.0,3.0
4.0,5.0,6.0
7.0,8.0,9.0
''';
Matrix matrix = await Matrix.fromCSV(csv: csv);
print(matrix);

// Alternatively, read the CSV from a file:
Matrix matrixFromFile = await Matrix.fromCSV(inputFilePath: 'input.csv');
print(matrixFromFile);

// Output:
// Matrix: 3x3
// ┌ 1.0 2.0 3.0 ┐
// │ 4.0 5.0 6.0 │
// └ 7.0 8.0 9.0 ┘

Write to a csv file

String csv = matrix.toCSV(outputFilePath: 'output.csv');
print(csv);

// Output:
// ```
// 1.0,2.0,3.0
// 4.0,5.0,6.0
// 7.0,8.0,9.0
// ```

to<->from Binary Data

You can serialize the matrix to a json-serializable map and deserialize back to a matrix object.

ByteData bd1 = matrix.toBinary(jsonFormat: false); // Binary format
ByteData bd2 = matrix.toBinary(jsonFormat: true); // JSON format

To restore a serialized matrix one may use Matrix.fromBinary constructor:

Matrix m1 = Matrix.fromBinary(bd1, jsonFormat: false); // Binary format
Matrix m2 = Matrix.fromBinary(bd2, jsonFormat: true); // JSON format

Matrix Operations

Perform matrix arithmetic operations:

Matrix a = Matrix([
  [1, 2],
  [3, 4]
]);

Matrix b = Matrix([
  [5, 6],
  [7, 8]
]);

// Addition of two square matrices
Matrix sum = a + b;
print(sum);
// Output:
// Matrix: 2x2
// ┌  6  8 ┐
// └ 10 12 ┘

// Addition of a matrix and a scalar
print(a + 2);
// Output:
// Matrix: 2x2
// ┌ 3 4 ┐
// └ 5 6 ┘

// Subtraction of two square matrices
Matrix difference = a - b;
print(difference);
// Output:
// Matrix: 2x2
// ┌ -4 -4 ┐
// └ -4 -4 ┘

// Matrix Scaler multiplication
Matrix scaler = a * 2;
print(scaler);
// Output:
// Matrix: 2x2
// ┌ 2 4 ┐
// └ 6 8 ┘

// Matrix dot product
Matrix product = a * Column([4,5]);
print(product);
// Output:
// Matrix: 2x1
// ┌ 14.0 ┐
// └ 32.0 ┘

// Matrix division
Matrix division = b / 2;
print(division);
// Output:
// Matrix: 2x2
// ┌ 2.5 3.0 ┐
// └ 3.5 4.0 ┘

// NB: For element-wise division, use elementDivision()
Matrix elementDivision = a.elementDivide(b);
print(elementDivision);
// Output:
// Matrix: 2x2
// ┌                 0.2 0.3333333333333333 ┐
// └ 0.42857142857142855                0.5 ┘

// Matrix exponent
Matrix expo = b ^ 2;
print(expo);
// Output:
// Matrix: 2x2
// ┌ 67  78 ┐
// └ 91 106 ┘

// Negate Matrix
Matrix negated = -a;
print(negated);
// Output:
// Matrix: 2x2
// ┌ -1 -2 ┐
// └ -3 -4 ┘

// Element-wise operation with function
var result = a.elementWise(b, (x, y) => x * y);
print(result);
// Output:
// Matrix: 2x2
// ┌  5 12 ┐
// └ 21 32 ┘

var matrix = Matrix([[-1, 2], [3, -4]]);
var abs = matrix.abs();
print(abs);
// Output:
// Matrix: 2x2
// ┌ 1 2 ┐
// └ 3 4 ┘

// Matrix Reciprocal round to 2 decimal places
var matrix = Matrix([[1, 2], [3, 4]]);
var reciprocal = matrix.reciprocal();
print(reciprocal.round(2));
// Output:
// Matrix: 2x2
// ┌                1.0  0.5 ┐
// └ 0.3333333333333333 0.25 ┘

// Round the elements to a decimal place
print(reciprocal.round(2));
// Output:
// Matrix: 2x2
// ┌  1.0  0.5 ┐
// └ 0.33 0.25 ┘

// Matrix dot product
var matrixB = Matrix([[2, 0], [1, 2]]);
var result = matrix.dot(matrixB);
print(result);
// Output:
// Matrix: 2x2
// ┌  4 4 ┐
// └ 10 8 ┘

// Determinant of a matrix
var determinant = matrix.determinant();
print(determinant); // Output: -2.0

// Inverse of Matrix
var inverse = matrix.inverse();
print(inverse);
// Output:
// Matrix: 2x2
// ┌ -0.5  1.5 ┐
// └  1.0 -2.0 ┘

// Transpose of a matrix
var transpose = matrix.transpose();
print(transpose);
// Output:
// Matrix: 2x2
// ┌ 4.0 2.0 ┐
// └ 3.0 1.0 ┘

// Find the normalized matrix
var normalize = matrix.normalize();
print(normalize);
// Output:
// Matrix: 2x2
// ┌ 1.0 0.75 ┐
// └ 0.5 0.25 ┘

// Norm of a matrix
var norm = matrix.norm();
print(norm); // Output: 5.477225575051661

// Sum of all the elements in a matrix
var sum = matrix.sum();
print(sum); // Output: 10

// determine the trace of a matrix
var trace = matrix.trace();
print(trace); // Output: 5

Assessing the elements of a matrix

Matrix can be accessed as components

var v = Matrix([
  [1, 2, 3],
  [4, 5, 6],
  [1, 3, 5]
]);
var b = Matrix([
  [7, 8, 9],
  [4, 6, 8],
  [1, 2, 3]
]);

var r = RowMatrix([7, 8, 9]);
var c = ColumnMatrix([7, 4, 1]);
var d = DiagonalMatrix([1, 2, 3]);

print(d);
// Output:
// 1 0 0
// 0 2 0
// 0 0 3

Change or use element value

v[1][2] = 0;

var u = v[1][2] + r[0][1];
print(u); // 9

var z = v[0][0] + c[0][0];
print(z); // 8

var y = v[1][2] + b[1][1];
print(y); // 9

var k = v.row(1); // Get all elements in row 1
print(k); // [1,2,3]

var n = v.column(1); // Get all elements in column 1
print(n); // [1,4,1]

Index (row,column) of an element in the matrix

var mat = Matrix.fromList([
  [2, 3, 3, 3],
  [9, 9, 8, 6],
  [1, 1, 2, 9]
]);

var index = mat.indexOf(8);
print(index);
// Output: [1, 2]

var indices = mat.indexOf(3, findAll: true);
print(indices);
// Output: [[0, 1], [0, 2], [0, 3]]

Access Row and Column

var mat = Matrix.fromList([
  [2, 3, 3, 3],
  [9, 9, 8, 6],
  [1, 1, 2, 9]
]);

print(mat[0]);
print(mat.row(0));

// Access column
print(mat.column(0));

// update row method 1
mat[0] = [1, 2, 3, 4];
print(mat);

// update row method 2
var v = mat.setRow(0, [4, 5, 6, 7]);
print(v);

// Update column
v = mat.setColumn(0, [1, 4, 5]);
print(v);

// Insert row
v = mat.insertRow(0, [8, 8, 8, 8]);
print(v);

// Insert column
v = mat.insertColumn(4, [8, 8, 8, 8]);
print(v);

// Delete row
print(mat.removeRow(0));

// Delete column
print(mat.removeColumn(0));

// Delete rows
mat.removeRows([0, 1]);

// Delete columns
mat.removeColumns([0, 2]);

Iterable objects from a matrix

You can get the iterable from a matrix object. Consider the matrix below:

var mat = Matrix.fromList([
  [2, 3, 3, 3],
  [9, 9, 8, 6],
  [1, 1, 2, 9]
]);

Iterate through the rows of the matrix using the default iterator

for (List<dynamic> row in mat.rows) {
  print(row);
}

Iterate through the columns of the matrix using the column iterator

for (List<dynamic> column in mat.columns) {
  print(column);
}

Iterate through the elements of the matrix using the element iterator

for (dynamic element in mat.elements) {
  print(element);
}

Iterate through elements in the matrix using foreach method

var m = Matrix([[1, 2], [3, 4]]);
m.forEach((x) => print(x));
// Output:
// 1
// 2
// 3
// 4

Partition of Matrix

// create a matrix
  Matrix m = Matrix([
    [1, 2, 3, 4, 5],
    [6, 7, 8, 9, 10],
    [5, 7, 8, 9, 10]
  ]);

// Extract a subMatrix with rows 1 to 2 and columns 1 to 2
Matrix sub = m.subMatrix(rowRange: "1:2", colRange: "0:1");

Matrix sub = m.subMatrix(rowStart: 1, rowEnd: 2, colStart: 0, colEnd: 1);

// sub-matrix will be:
// [
//   [6]
// ]

sub = m.subMatrix(rowList: [0, 2], colList: [0, 2, 4]);
// sub will be:
// [
//   [1, 3, 5],
//   [5, 8, 10]
// ]

sub = m.subMatrix(columnIndices: [4, 4, 2]);
 print("\nsub array: $sub");
// sub array: Matrix: 3x3
// ┌  5  5 3 ┐
// │ 10 10 8 │
// └ 10 10 8 ┘

// Get a sub-matrix
Matrix subMatrix = m.slice(0, 1, 1, 3);

Manipulating the matrix

Manipulate the matrices

  1. concatenate on axis 0
var l1 = Matrix([
  [1, 1, 1],
  [1, 1, 1],
  [1, 1, 1]
]);
var l2 = Matrix([
  [0, 0, 0],
  [0, 0, 0],
  [0, 0, 0],
  [0, 0, 0],
]);
var l3 = Matrix().concatenate([l1, l2]);
print(l3);
// Output:
// Matrix: 7x3
// ┌ 1 1 1 ┐
// │ 1 1 1 │
// │ 1 1 1 │
// │ 0 0 0 │
// │ 0 0 0 │
// │ 0 0 0 │
// └ 0 0 0 ┘
  1. concatenate on axis 1
var a1 = Matrix([
  [1, 1, 1, 1],
  [1, 1, 1, 1],
  [1, 1, 1, 1]
]);
var a2 = Matrix([
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]);

var a3 = Matrix().concatenate([a2, a1], axis: 1);

a3 = a2.concatenate([a1], axis: 1);
print(a3);
// Output:
// Matrix: 3x14
// ┌ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 ┐
// │ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 │
// └ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 ┘

Reshape the matrix

var matrix = Matrix([[1, 2], [3, 4]]);
var reshaped = matrix.reshape(1, 4);
print(reshaped);
// Output:
// 1  2  3  4

Solving Linear Systems of Equations

Use the solve method to solve a linear system of equations:

Matrix a = Matrix([[2, 1, 1], [1, 3, 2], [1, 0, 0]]);;

Matrix b = Matrix([[4], [5], [6]]);

// Solve the linear system Ax = b
Matrix x = a.linear.solve(b, method: LinearSystemMethod.gaussElimination);
print(x.round(1));
// Output:
// Matrix: 3x1
// ┌   6.0 ┐
// │  15.0 │
// └ -23.0 ┘

You can also use the the decompositions to solve a linear system of equations

Matrix A = Matrix([
  [4, 1, -1],
  [1, 4, -1],
  [-1, -1, 4]
]);
Matrix b = Matrix([
  [6],
  [25],
  [14]
]);

//Solve using the Schur Decomposition
SchurDecomposition schur = A.decomposition.schurDecomposition();

//Solve using the QR Decomposition Householder
QRDecomposition qr = A.decomposition.qrDecompositionHouseholder();

// Solve for x using the object
var x = qr.solve(b).round();
print(x);

// Output:
// Matrix: 3x1
// ┌ 1 ┐
// │ 7 │
// └ 6 ┘

Boolean Operations

Some functions in the library that results in boolean values

// Check contain or not
var matrix1 = Matrix([[1, 2], [3, 4]]);
var matrix2 = Matrix([[5, 6], [7, 8]]);
var matrix3 = Matrix([[1, 2, 3], [3, 4, 5], [5, 6, 7]]);
var targetMatrix = Matrix([[1, 2], [3, 4]]);

print(targetMatrix.containsIn([matrix1, matrix2])); // Output: true
print(targetMatrix.containsIn([matrix2, matrix3])); // Output: false

print(targetMatrix.notIn([matrix2, matrix3])); // Output: true
print(targetMatrix.notIn([matrix1, matrix2])); // Output: false

print(targetMatrix.isSubMatrix(matrix3)); // Output: true

Check Equality of Matrix

var m1 = Matrix([[1, 2], [3, 4]]);
var m2 = Matrix([[1, 2], [3, 4]]);
print(m1 == m2); // Output: true

print(m1.notEqual(m2)); // Output: false

Compare elements of Matrix

var m = Matrix.fromList([
    [2, 3, 3, 3],
    [9, 9, 8, 6],
    [1, 1, 2, 9]
  ]);
var result = Matrix.compare(m, '>', 2);
print(result);
// Output:
// Matrix: 3x4
// ┌ false  true  true true ┐
// │  true  true  true true │
// └ false false false true ┘

Sorting Matrix

Matrix x = Matrix.fromList([
  [2, 3, 3, 3],
  [9, 9, 8, 6],
  [1, 1, 2, 9],
  [0, 1, 1, 1]
]);

//Sorting all elements in ascending order (default behavior):
var sortedMatrix = x.sort();
print(sortedMatrix);
// Matrix: 4x4
// ┌ 0 1 1 1 ┐
// │ 1 1 2 2 │
// │ 3 3 3 6 │
// └ 8 9 9 9 ┘

// Sorting all elements in descending order:
var sortedMatrix1 = x.sort(ascending: false);
print(sortedMatrix1);
// Matrix: 4x4
// ┌ 9 9 9 8 ┐
// │ 6 3 3 3 │
// │ 2 2 1 1 │
// └ 1 1 1 0 ┘

// Sort by a single column in descending order
var sortedMatrix2 = x.sort(columnIndices: [0]);
print(sortedMatrix2);
// Matrix: 4x4
// ┌ 0 1 1 1 ┐
// │ 1 1 2 9 │
// │ 2 3 3 3 │
// └ 9 9 8 6 ┘

// Sort by multiple columns in specified orders
var sortedMatrix3 = x.sort(columnIndices: [1, 0]);
print(sortedMatrix3);
// Matrix: 4x4
// ┌ 0 1 1 1 ┐
// │ 1 1 2 9 │
// │ 2 3 3 3 │
// └ 9 9 8 6 ┘

// Sorting rows based on the values in column 2 (descending order):
Matrix xSortedColumn2Descending =
    x.sort(columnIndices: [2], ascending: false);
print(xSortedColumn2Descending);
// Matrix: 4x4
// ┌ 9 9 8 6 ┐
// │ 2 3 3 3 │
// │ 1 1 2 9 │
// └ 0 1 1 1 ┘

Roll Matrix

Roll elements along a given axis. Elements that roll beyond the last position are re-introduced at the first.

This function work exactly like the NumPy's roll.

  • shift : int or tuple of ints The number of places by which elements are shifted. If a tuple, then axis must be a tuple of the same size, and each of the given axes is shifted by the corresponding number. If an int while axis is a tuple of ints, then the same value is used for all given axes.
  • axis : int or tuple of ints or null Axis or axes along which elements are shifted. By default, the array is flattened before shifting, after which the original shape is restored.
Matrix x2 = Matrix([
  [0, 1, 2, 3, 4],
  [5, 6, 7, 8, 9]
]);

print(x2.roll(1));
// Matrix: 2x5
// ┌ 9 0 1 2 3 ┐
// └ 4 5 6 7 8 ┘

print(x2.roll(-1));
// Matrix: 2x5
// ┌ 1 2 3 4 5 ┐
// └ 6 7 8 9 0 ┘

print(x2.roll(1, axis: 0));
// Matrix: 2x5
// ┌ 5 6 7 8 9 ┐
// └ 0 1 2 3 4 ┘

print(x2.roll(-1, axis: 0));
// Matrix: 2x5
// ┌ 5 6 7 8 9 ┐
// └ 0 1 2 3 4 ┘

print(x2.roll(1, axis: 1));
// Matrix: 2x5
// ┌ 4 0 1 2 3 ┐
// └ 9 5 6 7 8 ┘

print(x2.roll(-1, axis: 1));
// Matrix: 2x5
// ┌ 1 2 3 4 0 ┐
// └ 6 7 8 9 5 ┘

print(x2.roll((1, 1), axis: (1, 0)));
// Matrix: 2x5
// ┌ 9 5 6 7 8 ┐
// └ 4 0 1 2 3 ┘

print(x2.roll((2, 1), axis: (1, 0)));
// Matrix: 2x5
// ┌ 8 9 5 6 7 ┐
// └ 3 4 0 1 2 ┘

print(x2.roll((1, 2), axis: (1, 0)));
// Matrix: 2x5
// ┌ 8 9 5 6 7 ┐
// └ 3 4 0 1 2 ┘

print(x2.roll((1, 2)));
// Matrix: 2x5
// ┌ 7 8 9 0 1 ┐
// └ 2 3 4 5 6 ┘

// Shift Value Larger than Matrix Size
print(x2.roll(7));
// Matrix: 2x5
// ┌ 3 4 5 6 7 ┐
// └ 8 9 0 1 2 ┘

Eigen Values and Vectors

var matr = Matrix.fromList([
  [4, 1, 1],
  [1, 4, 1],
  [1, 1, 4]
]);

var eigen = matr.eigen();
print('Eigen Values:\n${eigen.values}\n');
print('Eigenvectors:');
for (Matrix eigenvector in eigen.vectors) {
  print(eigenvector.round(1));
}

print('\nVerification: ${eigen.verify(matr)}');
print('Reconstruct Original:\n ${eigen.check}\n');

List<Matrix> normalizedEigenvectors =
    eigen.vectors.map((vector) => vector.normalize()).toList();
Eigen normalizedEigen = Eigen(eigen.values, normalizedEigenvectors);

print('Normalized eigenvectors:');
for (Matrix eigenvector in normalizedEigen.vectors) {
  print(eigenvector.round());
}
print('Reconstruct Original:\n ${normalizedEigen.check}\n');

eigen = Eigen([
    6,
    3,
    3
  ], [
  ColumnMatrix([1, 1, 1]),
  ColumnMatrix([-1, 1, 0]),
  ColumnMatrix([-1, 0, 1]),
]);
print('Check Matrix: ${eigen.check}');
Eigen Values:
[5.999999999999997, 2.9999999999999996, 3.000000000000001]

Eigenvectors:
Matrix: 3x1
┌ 0.6 ┐
│ 0.6 │
└ 0.6 ┘
Matrix: 3x1
┌ -0.7 ┐
│  0.7 │
└  0.0 ┘
Matrix: 3x1
┌ -0.4 ┐
│ -0.4 │
└  0.8 ┘

Verification: true
Reconstruct Original:
 Matrix: 3x3
┌  4.000000000058206 1.0000000000145517 1.0000000000145504 ┐
│ 1.0000000000145506 3.9999999999708953 0.9999999999708946 │
└ 1.0000000000145506 0.9999999999708964 3.9999999999708966 ┘

Normalized eigenvectors:
Matrix: 3x1
┌ 1 ┐
│ 1 │
└ 1 ┘
Matrix: 3x1
┌ -1 ┐
│  1 │
└  0 ┘
Matrix: 3x1
┌ 0 ┐
│ 0 │
└ 1 ┘

Reconstruct Original:
 Matrix: 3x3
┌  4.000000000058206 1.0000000000145512 1.0000000000145506 ┐
│ 1.0000000000145506 3.9999999999708953 0.9999999999708954 │
└ 1.0000000000145506 0.9999999999708962 3.9999999999708966 ┘

Check Matrix: Matrix: 3x3
┌ 4.0 1.0 1.0 ┐
│ 1.0 4.0 1.0 │
└ 1.0 1.0 4.0 ┘

Other Functions of matrices

The Matrix class provides various other functions for matrix manipulation and analysis.

// Swap rows
var matrix = Matrix([[1, 2], [3, 4]]);
matrix.swapRows(0, 1);
print(matrix);
// Output:
// Matrix: 2x2
// ┌ 3 4 ┐
// └ 1 2 ┘

// Swap columns
matrix.swapColumns(0, 1);
print(matrix);
// Output:
// Matrix: 2x2
// ┌ 4 3 ┐
// └ 2 1 ┘

// Get the leading diagonal of the matrix
var m = Matrix([[1, 2], [3, 4]]);
var diag = m.diagonal();
print(diag);
// Output: [1, 4]

// Iterate through elements in the matrix using map function
var doubled = m.map((x) => x * 2);
print(doubled);
// Output:
// Matrix: 2x2
// ┌ 2 4 ┐
// └ 6 8 ┘
VECTOR

Create a new vector

  • Vector(int length, {bool isDouble = true}): Creates a [Vector] of given length with all elements initialized to 0.
  • Vector.fromList(List<num> data): Constructs a [Vector] from a list of numerical values.
  • Vector.random(int length,{double min = 0, double max = 1, bool isDouble = true, math.Random? random, int? seed}): Constructs a [Vector] from a list of random numerical values.
  • Vector.linspace(int start, int end, [int number = 50]): Creates a row Vector with equally spaced values between the start and end values (inclusive).
  • Vector.range(int end, {int start = 1, int step = 1}) & Vector.arrange(int end, {int start = 1, int step = 1}): Creates a Vector with values in the specified range, incremented by the specified step size.
// Create a vector of length 3 with all elements initialized to 0
var v1 = Vector(3);

// Create a vector from a list of values
var v2 = Vector([1, 2, 3]);
v2 = Vector.fromList([1, 2, 3]);

// Create a vector with random values between 0 and 1
var v3 = Vector.random(3);

// Create a vector with 50 values equally spaced between 0 and 1
var v4 = Vector.linspace(0, 1);

// Create a vector with values 1, 3, 5, 7, 9
var v5 = Vector.range(10, start: 1, step: 2);
v5 = Vector.arrange(10, start: 1, step: 2);

Operators

Supports operations for element-wise operations by scalar value or vector

// Get the value at index 2 of v2
var val = v2[2];

// Set the value at index 1 of v1 to 7
v1[1] = 7;

// Add v1 and v2
var v6 = v1 + v2;

// Subtract v2 from v1
var v7 = v1 - v2;

// Multiply v1 by a scalar
var v8 = v1 * 3.5;

// Divide v2 by a scalar
var v9 = v2 / 2;

Vector Operations

  • double dot(Vector other): Calculates the dot product of the vector with another vector.
  • Vector cross(Vector other): Calculates the cross product of the vector with another vector.
  • double get magnitude: Returns the magnitude (or norm) of the vector.
  • double get direction: Returns the direction (or angle) of the vector, in radians.
  • double norm(): Returns the norm (or length) of this vector.
  • Vector normalize(): Returns this vector normalized.
  • bool isZero(): Returns true if this is a zero vector, i.e., all its elements are zero.
  • bool isUnit(): Returns true if this is a unit vector, i.e., its norm is 1.
// Calculate the dot product of v1 and v2
var dotProduct = v1.dot(v2);

// Calculate the cross product of two 3D vectors
var crossProduct = Vector.fromList([1, 2, 3]).cross(Vector.fromList([4, 5, 6]));

// Get the magnitude of v1
var magnitude = v1.magnitude;

// Get the direction of v1
var direction = v1.direction;

// Get the norm of v1
var norm = v1.norm();

// Normalize v1
var normalizedV1 = v1.normalize();

Others metrics include:

  • List<num> toList(): Converts the vector to a list of numerical values.
  • int get length: Returns the length (number of elements) of the vector.
  • void setAll(num value): Sets all elements of this vector to [value].
  • double distance(Vector other): Returns the Euclidean distance between this vector and [other].
  • Vector projection(Vector other): Returns the projection of this vector onto [other].
  • double angle(Vector other): Returns the angle (in radians) between this vector and [other].
  • List<double> toSpherical(): Converts the Vector from Cartesian to Spherical coordinates.
  • void fromSpherical(List<num> sphericalCoordinates): Converts the Vector from Spherical to Cartesian coordinates.
Vector v = Vector([1, 2, 3]);
print(v);  // Output: [1, 2, 3]

// Convert v1 to a list
var list = v1.toList();

// Get the length of v1
var length = v1.length;

// Set all elements of v1 to 5
v1.setAll(5);

// Calculate the Euclidean distance between v1 and v2
var distance = v1.distance(v2);

// Calculate the projection of v1 onto v2
var projection = v1.projection(v2);

// Calculate the angle between v1 and v2
var angle = v1.angle(v2);

// Convert v1 to spherical coordinates
var spherical = v1.toSpherical();

// Create a vector from spherical coordinates
var v10 = Vector(3);
v10.fromSpherical(spherical);

Vector Subset

// Extraction
var u1 = Vector.fromList([5, 0, 2, 4]);
var v1 = u1.getVector(['x', 'x', 'y']);
print(v1); // Output: [5.0, 5.0, 0.0)]
print(v1.runtimeType); // Vector3

u1 = Vector.fromList([5, 0, 2]);
v1 = u1.subVector(range: '1:2');
print(v1); // Output: [5.0, 5.0, 0.0, 2.0]
print(v1.runtimeType); // Vector4

var v = Vector.fromList([1, 2, 3, 4, 5]);
var subVector = v.subVector(indices: [0, 2, 4, 1, 1]);
print(subVector);  // Output: [1.0, 3.0, 5.0, 2.0, 2.0]
print(subVector.runtimeType); // Vector

It's possible to use vector instances as keys for HashMap and similar data structures and to look up a value by the vector-key, since the hash code for equal vectors is the same.

final map = HashMap<Vector, bool>();

map[Vector.fromList([1, 2, 3, 4, 5])] = true;

print(map[Vector.fromList([1, 2, 3, 4, 5])]); // true
print(Vector.fromList([1, 2, 3, 4, 5]).hashCode ==
      Vector.fromList([1, 2, 3, 4, 5]).hashCode); // true

Additional features

var xx = Vector([1, 2, 3, 4]);
var yy = Vector([4, 5]);
print('');
print(xx.outerProduct(yy));
// Matrix: 4x2
// ┌  4  5 ┐
// │  8 10 │
// │ 12 15 │
// └ 16 20 ┘

var mat = Matrix.fromList([
  [2, 3, 3, 3],
  [9, 9, 8, 6],
  [1, 1, 2, 9]
]);

print(-Vector([1, 2, 3]) + mat);
// Matrix: 3x4
// ┌  1  2  2 2 ┐
// │  7  7  6 4 │
// └ -2 -2 -1 6 ┘

print(xx * mat + xx.subVector(end: xx.length - 2)); // [30.0, 77.0, 48.0]

//Vector operations
final vector1 = Vector([1.0, 2.0, 3.0, 4.0, 5.0]);
final vector2 = Vector.fromList([2.0, 3.0, 4.0, 5.0, 6.0]);
final result1 = vector1.distance(vector2, distance: DistanceType.cosine);
print(result1); // 0.005063323673817899

var result = vector1.normalize();
print(result.round(3)); // [0.135, 0.270, 0.405, 0.539, 0.674]

final vector = Vector.fromList([1.0, -2.0, 3.0, -4.0, 5.0]);
result = vector.normalize(Norm.manhattan);
print(result.round(3)); // [0.067, -0.133, 0.200, -0.267, 0.333]

var result2 = vector1.rescale();
print(result2); // [0.0, 0.25, 0.5, 0.75, 1.0]

var vector3 = Vector.fromList([4.0, 5.0, 6.0, 7.0, 8.0]);
result = vector3 - [2.0, 3.0, 2.0, 3.0, 2.0];
print(result); // [2.0, 2.0, 4.0, 4.0, 6.0]
COMPLEX NUMBERS & COMPLEX VECTORS

Complex Numbers and ComplexVectors

This library provides efficient and easy-to-use classes for representing and manipulating vectors, complex numbers, and complex vectors in Dart. This document serves as an introduction to these classes, featuring a variety of examples to demonstrate their usage.

Complex Numbers

Complex numbers extend the concept of the one-dimensional number line to the two-dimensional complex plane by using the number i, where i^2 = -1.

Complex numbers are crucial in many areas of mathematics and engineering.

The Complex class in this library lets you create complex numbers, access their real and imaginary parts, and obtain their conjugate.

Constructors

The class provides several constructors to create complex numbers in different ways:

var z1 = Complex(1, 2); // Creates a complex number 1 + 2i
var z2 = Complex.fromPolar(2, pi / 2); // Creates a complex number from polar coordinates
var z3 = Complex.fromReal(1); // Creates a complex number with only a real part
var z4 = Complex.fromImaginary(2); // Creates a complex number with only an imaginary part
var z5 = Complex.parse('2 + 2i'); // Parses a complex number from a string

Access its properties

// Creating a new complex number
Complex z = Complex(3, 2);
print(z);  // Output: 3 + 2i

// Accessing the real and imaginary parts
print(z.real);  // Output: 3
print(z.imaginary);  // Output: 2

// Conjugation
Complex conjugate = z.conjugate();
print(conjugate);  // Output: 3 - 2i

Operations

The class supports all basic arithmetic operations, including addition, subtraction, multiplication, division, and exponentiation:

var z1 = Complex(1, 2);
var z2 = Complex(2, 3);

var sum = z1 + z2; // Adds two complex numbers
var difference = z1 - z2; // Subtracts two complex numbers
var product = z1 * z2; // Multiplies two complex numbers
var quotient = z1 / z2; // Divides two complex numbers
var mod = z1 % 2; // Modulo operation of complex numbers
var power = z1 ^ 2; // Raises a complex number to a power

Power Operator

The power operator (^) raises the complex number to the power of the given number. The result is another complex number.

var z = Complex(2, 3); // 2 + 3i
var z_power = z ^ 2;

print(z_power); // Output: -5 + 12i

In this example, the complex number z is raised to the power of 2. The result is another complex number -5 + 12i.

var z = Complex(1, 2); // 1 + 2i
var z_power = z ^ Complex(2, 1); // (2 + i)

print(z_power); // Output: -1.6401010184280038 + 0.202050398556709i

In this example, the complex number z is raised to the power of another complex number 2 + i. The result is another complex number -1.6401010184280038 + 0.202050398556709i.

Other methods

The class also provides several other methods to work with complex numbers

var z = Complex(1, 2);

var magnitude = z.magnitude; // Gets the magnitude (or absolute value) of the complex number
var angle = z.angle; // Gets the angle (or argument or phase) in radians of the complex number
var conjugate = z.conjugate; // Gets the conjugate of the complex number
var real = z.real; // Gets the real part of the complex number
var imaginary = z.imaginary; // Gets the imaginary part of the complex number
var sqrt = z.sqrt(); // Gets the square root of the complex number
var exp = z.exp(); // Gets the exponential of the complex number
var ln = z.ln(); // Gets the natural logarithm (base e) of the complex number
var sin = z.sin(); // Gets the sine of the complex number
var cos = z.cos(); // Gets the cosine of the complex number
var tan = z.tan(); // Gets the tangent of the complex number

Complex vectors

ComplexVectors are a type of vector where the elements are complex numbers. They are especially important in quantum mechanics and signal processing.

The ComplexVector class provides ways to create complex vectors, perform operations on them such as addition, and calculate their norm and normalized form.

// Creating a new complex vector
ComplexVector cv = ComplexVector(2);
cv[0] = Complex(1, 2);
cv[1] = Complex(3, 4);
print(cv);  // Output: [(1 + 2i), (3 + 4i)]

// Accessing elements
print(cv[0]);  // Output: 1 + 2i

// Vector operations (example: addition)
ComplexVector cv2 = ComplexVector.fromList([Complex(5, 6), Complex(7, 8)]);
ComplexVector sum = cv + cv2;
print(sum);  // Output: [(6 + 8i), (10 + 12i)]

// Norm and normalization
double norm = cv.norm();
ComplexVector normalized = cv.normalize();
print(norm);  // Output: 5.477225575051661
print(normalized);  // Output: [(0.18257418583505536 + 0.3651483716701107i), (0.5477225575051661 + 0.7302967433402214i)]

The above sections provide a basic introduction to vectors, complex numbers, and complex vectors. The full API of these classes offers even more possibilities, including conversions to other forms of vectors, multiplication by scalars, and more. These classes aim to make mathematical programming in Dart efficient, flexible, and enjoyable.

DATAFRAMES

DataFrame

A class representing a DataFrame, which is a 2-dimensional labeled data structure with columns of potentially different types.

Introduction

The DataFrame class in Dart provides functionalities similar to data frames in languages like Python and R. It allows you to work with structured data, perform data manipulations, and conduct data analysis efficiently.

Usage

To use the DataFrame class, you can create an instance by providing column names and data:

var columnNames = ['Name', 'Age', 'City'];
var data = [
  ['Alice', 30, 'New York'],
  ['Bob', 25, 'Los Angeles'],
  ['Charlie', 35, 'Chicago'],
];
var df = DataFrame(columns:columnNames, data: data);

You can also create a DataFrame from a CSV string or a JSON string:

var csvData = 'Name,Age,City\nAlice,30,New York\nBob,25,Los Angeles\nCharlie,35,Chicago';
var dfFromCSV = DataFrame.fromCSV(csv: csvData, delimiter: ',');

var jsonData = '[{"Name": "Alice", "Age": 30, "City": "New York"}, '
                '{"Name": "Bob", "Age": 25, "City": "Los Angeles"}, '
                '{"Name": "Charlie", "Age": 35, "City": "Chicago"}]';
var dfFromJSON = DataFrame.fromJson(jsonString: jsonData);

Features

  • DataFrame

  • Create DataFrames from lists, CSV files, JSON data, or from a map.

  • Access columns by name or index.

  • Select, filter, sort, and group data.

  • Perform calculations and transformations (mean, standard deviation, etc.).

  • Add, remove, and modify rows and columns.

  • Merge/concatenate DataFrames.

  • Handle missing data.

  • Count the number of zeros and null values in a specified column.

  • Limit the DataFrame to a specified number of rows.

  • Replace occurrences of values in the DataFrame.

  • Series

  • Create Series with various data types.

  • Perform element-wise operations (+, -, *, /, etc.).

  • Apply transformations (square, convert to string, etc.).

  • Basic statistical analysis (mean, std, min, max, quantiles).

  • Concatenate Series.

Example

var df = DataFrame(
  columns:['Name', 'Age', 'City'], 
  data: [
  ['Alice', 30, 'New York'],
  ['Bob', 25, 'Los Angeles'],
  ['Charlie', 35, 'Chicago'],
]);

print(df.toString());

This will output:

Name    Age   City        
Alice   30    New York    
Bob     25    Los Angeles 
Charlie 35    Chicago     

Access and update elements

Series numbers = Series([1, 2, 3, 4], name: "Numbers");

// Update a single element
numbers[1] = 10;

// Update multiple elements
numbers[[0, 2]] = [5, 6];

// Update based on a condition
numbers[numbers > 7] = 99;

print(numbers); //Numbers: [5, 99, 6, 4]

Concatenate series

// Series concatenation
Series s1 = Series([1, 2, 3], name: 'A');
Series s2 = Series([4, 5, 6], name: 'B');

// Vertical concatenation
Series s_vertical = s1.concatenate(s2);
print(s_vertical); // A - B: [1, 2, 3, 4, 5, 6]

// Horizontal concatenation
Series s_horizontal = s1.concatenate(s2, axis: 1);
print(s_horizontal); // A - B: [1, 2, 3, 4, 5, 6]

Similarly for DataFrames

// DataFrame concatenation
var df1 = DataFrame(
  columns: ['A','B'], 
  data: [
    [1, 2],
    [3, 4]
  ]
);
var df2 = DataFrame(
  columns: ['A','B'], 
  data: [
    [5, 6],
    [7, 8]
  ]
);
var df3 = DataFrame(
  columns: ['C', 'D' ], 
  data: [
    [10, 11],
    [12, 13]
  ]
);

// Vertical concatenation
var df_vertical = df1.concatenate(df2);
print(df_vertical);

// A  B  
// 1  2  
// 3  4  
// 5  6  
// 7  8  

// Horizontal concatenation
var df_horizontal = df1.concatenate(df3, axis: 1);
print(df_horizontal);

// A  B  C   D   
// 1  2  10  11  
// 3  4  12  13  

Testing

Tests are located in the test directory. To run tests, execute dart test in the project root.

Contributing Features and bugs

🍺 Pull requests are welcome

Don't forget that open-source makes no sense without contributors. No matter how big your changes are, it helps us a lot even it is a line of change.

There might be a lot of grammar issues in the docs. It's a big help to us to fix them if you are fluent in English.

Reporting bugs and issues are contribution too, yes it is.

Please file feature requests and bugs at the issue tracker.

Author

Charles Gameti: gameticharles@GitHub.

License

This library is provided under the Apache License - Version 2.0.

About

Advance math is a comprehensive Dart library that enriches mathematical programming in Dart with a wide range of features beyond vectors and matrices.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages