Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
matrix_example.C
Go to the documentation of this file.
1
141#include <iostream>
142#include <iomanip>
143#include <string>
144#include <memory>
145
146#include <tclap/CmdLine.h>
147
148#include <al-vector.H>
149#include <al-matrix.H>
150#include <al-domain.H>
151#include <htlist.H>
152#include <ahFunctional.H>
153
154using namespace std;
155using namespace Aleph;
156
157// =============================================================================
158// Helper functions
159// =============================================================================
160
161void print_section(const string& title)
162{
163 cout << "\n" << string(60, '=') << "\n";
164 cout << " " << title << "\n";
165 cout << string(60, '=') << "\n\n";
166}
167
168void print_subsection(const string& title)
169{
170 cout << "\n--- " << title << " ---\n";
171}
172
173// =============================================================================
174// 1. Sparse Vector Basics
175// =============================================================================
176
178{
179 print_section("SPARSE VECTOR BASICS");
180
181 // Create a domain for the vector indices
182 print_subsection("Creating a Sparse Vector");
183
184 // Create domain with elements 0-9
185 auto domain = make_shared<AlDomain<int>>();
186 for (int i = 0; i < 10; i++)
187 (void)domain->insert(i);
188
189 // Create sparse vector with this domain
190 Vector<int, double> v(domain);
191
192 cout << "Created sparse vector with domain {0, 1, ..., 9}" << endl;
193 cout << "Initial storage: only non-zero elements are stored" << endl;
194
195 // Set some values
196 print_subsection("Setting Values");
197 v.set_entry(0, 1.5);
198 v.set_entry(3, 2.7);
199 v.set_entry(7, -4.2);
200
201 cout << "Set v[0] = 1.5, v[3] = 2.7, v[7] = -4.2" << endl;
202 cout << "\nNon-zero entries:" << endl;
203 for (auto it = v.get_it(); it.has_curr(); it.next())
204 {
205 auto entry = it.get_curr();
206 cout << " v[" << entry.first << "] = " << entry.second << endl;
207 }
208
209 // Access values
210 print_subsection("Accessing Values");
211 cout << "v[0] = " << v.get_entry(0) << endl;
212 cout << "v[3] = " << v.get_entry(3) << endl;
213 cout << "v[5] = " << v.get_entry(5) << " (not set, returns 0)" << endl;
214
215 // Count non-zero entries
216 size_t nnz = 0;
217 for (auto it = v.get_it(); it.has_curr(); it.next())
218 nnz++;
219 cout << "\nNumber of non-zero entries: " << nnz << endl;
220 cout << "Memory savings: only storing " << nnz << " of 10 possible values" << endl;
221}
222
223// =============================================================================
224// 2. String-Indexed Vectors
225// =============================================================================
226
228{
229 print_section("STRING-INDEXED VECTORS");
230
231 cout << "Vectors can be indexed by ANY type, not just integers!" << endl;
232
233 // Create a domain with Colombian city names
235 (void)cities->insert("Bogota");
236 (void)cities->insert("Medellin");
237 (void)cities->insert("Cali");
238 (void)cities->insert("Barranquilla");
239 (void)cities->insert("Cartagena");
240
241 // Create a population vector (in millions)
242 Vector<string, double> population(cities);
243 population.set_entry("Bogota", 7.4);
244 population.set_entry("Medellin", 2.5);
245 population.set_entry("Cali", 2.2);
246 population.set_entry("Barranquilla", 1.2);
247 // Cartagena not set - will be 0
248
249 cout << "\nColombian city populations (millions):" << endl;
250 for (auto it = population.get_it(); it.has_curr(); it.next())
251 {
252 auto entry = it.get_curr();
253 cout << " " << setw(15) << left << entry.first
254 << ": " << entry.second << "M" << endl;
255 }
256
257 cout << "\nCartagena (not set): " << population.get_entry("Cartagena") << "M" << endl;
258
259 // Scalar multiplication
260 print_subsection("Scalar Operations");
261 auto doubled = population * 2.0;
262 cout << "Population * 2:" << endl;
263 for (auto it = doubled.get_it(); it.has_curr(); it.next())
264 {
265 auto entry = it.get_curr();
266 cout << " " << setw(15) << left << entry.first
267 << ": " << entry.second << "M" << endl;
268 }
269}
270
271// =============================================================================
272// 3. Sparse Matrix Basics
273// =============================================================================
274
276{
277 print_section("SPARSE MATRIX BASICS");
278
279 // Create row and column domains
280 auto rows = make_shared<AlDomain<int>>();
281 auto cols = make_shared<AlDomain<int>>();
282
283 for (int i = 0; i < 5; i++)
284 {
285 (void)rows->insert(i);
286 (void)cols->insert(i);
287 }
288
289 // Create 5x5 sparse matrix
290 Matrix<int, int, double> M(rows, cols);
291
292 print_subsection("Creating a Sparse 5x5 Matrix");
293 cout << "Matrix is 5x5 but only non-zero entries are stored" << endl;
294
295 // Set diagonal and a few off-diagonal entries
296 M.set_entry(0, 0, 1.0);
297 M.set_entry(1, 1, 2.0);
298 M.set_entry(2, 2, 3.0);
299 M.set_entry(3, 3, 4.0);
300 M.set_entry(4, 4, 5.0);
301 // Some off-diagonal
302 M.set_entry(0, 1, 0.5);
303 M.set_entry(1, 2, 0.5);
304
305 cout << "\nNon-zero entries:" << endl;
306 // Print diagonal
307 for (int i = 0; i < 5; i++)
308 cout << " M[" << i << "][" << i << "] = " << M.get_entry(i, i) << endl;
309 cout << " M[0][1] = " << M.get_entry(0, 1) << endl;
310 cout << " M[1][2] = " << M.get_entry(1, 2) << endl;
311
312 // Count entries manually
313 size_t nnz = 7; // We set 7 entries above
314 cout << "\nStored entries: " << nnz << " out of " << (5*5)
315 << " possible (" << (100.0 * nnz / 25) << "% fill)" << endl;
316}
317
318// =============================================================================
319// 4. Named Row/Column Matrix (Practical Example)
320// =============================================================================
321
323{
324 print_section("NAMED ROW/COLUMN MATRIX");
325
326 cout << "Sparse matrices are perfect for real-world data with named dimensions" << endl;
327
328 // Sales data: products vs stores
330 (void)products->insert("Laptop");
331 (void)products->insert("Phone");
332 (void)products->insert("Tablet");
333 (void)products->insert("Monitor");
334
336 (void)stores->insert("BOG"); // Bogota
337 (void)stores->insert("MED"); // Medellin
338 (void)stores->insert("CAL"); // Cali
339 (void)stores->insert("BAQ"); // Barranquilla
340
342
343 // Set some sales data (not all products sold in all stores)
344 sales.set_entry("Laptop", "BOG", 150);
345 sales.set_entry("Laptop", "MED", 120);
346 sales.set_entry("Phone", "BOG", 500);
347 sales.set_entry("Phone", "MED", 450);
348 sales.set_entry("Phone", "CAL", 300);
349 sales.set_entry("Phone", "BAQ", 200);
350 sales.set_entry("Tablet", "BOG", 80);
351 sales.set_entry("Monitor", "MED", 50);
352
353 cout << "\nSales data (only non-zero entries stored):" << endl;
354 cout << string(45, '-') << endl;
355
356 // Print some entries manually
357 cout << " Laptop @ BOG: " << sales.get_entry("Laptop", "BOG") << " units" << endl;
358 cout << " Laptop @ MED: " << sales.get_entry("Laptop", "MED") << " units" << endl;
359 cout << " Phone @ BOG: " << sales.get_entry("Phone", "BOG") << " units" << endl;
360 cout << " Phone @ MED: " << sales.get_entry("Phone", "MED") << " units" << endl;
361 cout << " Phone @ CAL: " << sales.get_entry("Phone", "CAL") << " units" << endl;
362 cout << " Phone @ BAQ: " << sales.get_entry("Phone", "BAQ") << " units" << endl;
363 cout << " Tablet @ BOG: " << sales.get_entry("Tablet", "BOG") << " units" << endl;
364 cout << " Monitor @ MED:" << sales.get_entry("Monitor", "MED") << " units" << endl;
365
366 // Get a column (all products for a store)
367 print_subsection("Column Extraction: Bogota Store Sales");
368 auto bog_sales = sales.get_col_vector("BOG");
369 cout << "Products sold in Bogota:" << endl;
370 for (auto it = bog_sales.get_it(); it.has_curr(); it.next())
371 {
372 auto entry = it.get_curr();
373 cout << " " << setw(10) << left << entry.first
374 << ": " << entry.second << " units" << endl;
375 }
376
377 // Get a row (all stores for a product)
378 print_subsection("Row Extraction: Phone Sales");
379 auto phone_sales = sales.get_row_vector("Phone");
380 cout << "Phone sales by store:" << endl;
381 for (auto it = phone_sales.get_it(); it.has_curr(); it.next())
382 {
383 auto entry = it.get_curr();
384 cout << " " << setw(5) << left << entry.first
385 << ": " << entry.second << " units" << endl;
386 }
387}
388
389// =============================================================================
390// 5. Vector Arithmetic
391// =============================================================================
392
394{
395 print_section("VECTOR ARITHMETIC");
396
397 // Create two vectors
398 auto domain = make_shared<AlDomain<int>>();
399 for (int i = 0; i < 5; i++)
400 (void)domain->insert(i);
401
402 Vector<int, double> a(domain);
403 Vector<int, double> b(domain);
404
405 a.set_entry(0, 1.0);
406 a.set_entry(1, 2.0);
407 a.set_entry(2, 3.0);
408
409 b.set_entry(1, 1.5);
410 b.set_entry(2, 2.5);
411 b.set_entry(3, 3.5);
412
413 auto print_vec = [](const string& name, const Vector<int, double>& v) {
414 cout << name << ": ";
415 for (auto it = v.get_it(); it.has_curr(); it.next())
416 {
417 auto e = it.get_curr();
418 cout << "(" << e.first << ":" << e.second << ") ";
419 }
420 cout << endl;
421 };
422
423 print_vec("a", a);
424 print_vec("b", b);
425
426 // Addition
427 print_subsection("Vector Addition");
428 auto sum = a + b;
429 print_vec("a + b", sum);
430 cout << " Note: sparse + sparse = sparse (union of indices)" << endl;
431
432 // Scalar multiplication
433 print_subsection("Scalar Multiplication");
434 auto scaled = a * 2.0;
435 print_vec("a * 2", scaled);
436
437 // Subtraction
438 print_subsection("Vector Subtraction");
439 auto diff = a - b;
440 print_vec("a - b", diff);
441}
442
443// =============================================================================
444// 6. Practical Application: Graph Adjacency Matrix
445// =============================================================================
446
448{
449 print_section("PRACTICAL: GRAPH ADJACENCY MATRIX");
450
451 cout << "Sparse matrices are ideal for representing graphs" << endl;
452 cout << "Most graphs are sparse (few edges vs all possible edges)" << endl;
453
454 // Create nodes domain
456 (void)nodes->insert("A");
457 (void)nodes->insert("B");
458 (void)nodes->insert("C");
459 (void)nodes->insert("D");
460 (void)nodes->insert("E");
461
462 // Adjacency matrix with weights
464
465 // Add edges (directed graph)
466 adj.set_entry("A", "B", 4);
467 adj.set_entry("A", "C", 2);
468 adj.set_entry("B", "C", 1);
469 adj.set_entry("B", "D", 5);
470 adj.set_entry("C", "D", 8);
471 adj.set_entry("C", "E", 10);
472 adj.set_entry("D", "E", 2);
473
474 cout << "\nGraph edges (weighted):" << endl;
475 cout << " A -> B : weight " << adj.get_entry("A", "B") << endl;
476 cout << " A -> C : weight " << adj.get_entry("A", "C") << endl;
477 cout << " B -> C : weight " << adj.get_entry("B", "C") << endl;
478 cout << " B -> D : weight " << adj.get_entry("B", "D") << endl;
479 cout << " C -> D : weight " << adj.get_entry("C", "D") << endl;
480 cout << " C -> E : weight " << adj.get_entry("C", "E") << endl;
481 cout << " D -> E : weight " << adj.get_entry("D", "E") << endl;
482
483 // Count edges
484 size_t num_edges = 7; // We set 7 edges above
485
486 size_t num_nodes = 5;
487 size_t max_edges = num_nodes * num_nodes;
488
489 cout << "\nGraph statistics:" << endl;
490 cout << " Nodes: " << num_nodes << endl;
491 cout << " Edges: " << num_edges << endl;
492 cout << " Density: " << fixed << setprecision(1)
493 << (100.0 * num_edges / max_edges) << "%" << endl;
494 cout << " Memory: storing only " << num_edges
495 << " values instead of " << max_edges << endl;
496
497 // Find outgoing edges from a node
498 print_subsection("Outgoing Edges from Node B");
499 auto b_out = adj.get_row_vector("B");
500 for (auto it = b_out.get_it(); it.has_curr(); it.next())
501 {
502 auto entry = it.get_curr();
503 cout << " B -> " << entry.first << " : " << entry.second << endl;
504 }
505}
506
507// =============================================================================
508// 7. Epsilon Tolerance
509// =============================================================================
510
512{
513 print_section("EPSILON TOLERANCE");
514
515 cout << "Sparse vectors/matrices automatically handle near-zero values" << endl;
516
517 auto domain = make_shared<AlDomain<int>>();
518 for (int i = 0; i < 5; i++)
519 (void)domain->insert(i);
520
521 Vector<int, double> v(domain);
522
523 // Get current epsilon
524 cout << "\nDefault epsilon: " << v.get_epsilon() << endl;
525
526 v.set_entry(0, 1.0);
527 v.set_entry(1, 0.0001); // Very small
528 v.set_entry(2, 0.0); // Exact zero
529
530 cout << "\nAfter setting v[0]=1.0, v[1]=0.0001, v[2]=0.0:" << endl;
531 for (auto it = v.get_it(); it.has_curr(); it.next())
532 {
533 auto entry = it.get_curr();
534 cout << " v[" << entry.first << "] = " << entry.second << endl;
535 }
536
537 cout << "\nNote: v[2]=0.0 is not stored (it's zero)" << endl;
538 cout << "v[1]=0.0001 is stored because |0.0001| > epsilon" << endl;
539
540 // Change epsilon
541 print_subsection("Changing Epsilon");
542 v.set_epsilon(0.001);
543 cout << "New epsilon: " << v.get_epsilon() << endl;
544
545 // Now set a value smaller than epsilon
546 v.set_entry(3, 0.0005);
547 cout << "\nAfter setting v[3]=0.0005 (< epsilon):" << endl;
548 for (auto it = v.get_it(); it.has_curr(); it.next())
549 {
550 auto entry = it.get_curr();
551 cout << " v[" << entry.first << "] = " << entry.second << endl;
552 }
553 cout << "\nv[3] was not stored because 0.0005 < 0.001 (epsilon)" << endl;
554}
555
556// =============================================================================
557// 8. Initializer List Construction
558// =============================================================================
559
561{
562 print_section("INITIALIZER LIST CONSTRUCTION");
563
564 cout << "Matrices can be constructed directly from initializer lists" << endl;
565 cout << "(similar to how you'd write a matrix on paper)" << endl;
566
567 // Create domains for a 3x3 matrix
568 auto rows = make_shared<AlDomain<int>>();
569 auto cols = make_shared<AlDomain<int>>();
570 for (int i = 0; i < 3; i++)
571 {
572 (void)rows->insert(i);
573 (void)cols->insert(i);
574 }
575
576 // Create matrix with initializer list
577 Matrix<int, int, double> A(rows, cols, {
578 {1, 2, 3},
579 {4, 5, 6},
580 {7, 8, 9}
581 });
582
583 cout << "\nMatrix A (from initializer list):" << endl;
584 cout << A.to_str() << endl;
585
586 // Sparse matrix - zeros are not stored
587 print_subsection("Sparse Initializer List");
588 Matrix<int, int, double> B(rows, cols, {
589 {1, 0, 0},
590 {0, 2, 0},
591 {0, 0, 3}
592 });
593
594 cout << "\nDiagonal matrix B (zeros not stored internally):" << endl;
595 cout << B.to_str() << endl;
596 cout << "\nNote: only 3 entries are stored (the diagonal)" << endl;
597}
598
599// =============================================================================
600// 9. Matrix Transpose
601// =============================================================================
602
604{
605 print_section("MATRIX TRANSPOSE");
606
607 cout << "The transpose() method swaps rows and columns" << endl;
608
609 // Create a 2x3 matrix
610 auto rows = make_shared<AlDomain<string>>();
611 auto cols = make_shared<AlDomain<string>>();
612 (void)rows->insert("r0");
613 (void)rows->insert("r1");
614 (void)cols->insert("c0");
615 (void)cols->insert("c1");
616 (void)cols->insert("c2");
617
618 Matrix<string, string, double> M(rows, cols);
619 M.set_entry("r0", "c0", 1); M.set_entry("r0", "c1", 2); M.set_entry("r0", "c2", 3);
620 M.set_entry("r1", "c0", 4); M.set_entry("r1", "c1", 5); M.set_entry("r1", "c2", 6);
621
622 cout << "\nOriginal matrix M (2x3):" << endl;
623 cout << M.to_str() << endl;
624
625 auto Mt = M.transpose();
626 cout << "\nTranspose M^T (3x2):" << endl;
627 cout << Mt.to_str() << endl;
628
629 cout << "\nProperty: M[r][c] = M^T[c][r]" << endl;
630 cout << " M[r0][c2] = " << M.get_entry("r0", "c2") << endl;
631 cout << " M^T[c2][r0] = " << Mt.get_entry("c2", "r0") << endl;
632}
633
634// =============================================================================
635// 10. Identity Matrix
636// =============================================================================
637
639{
640 print_section("IDENTITY MATRIX");
641
642 cout << "The identity() method creates I (only for square matrices)" << endl;
643 cout << "Property: A * I = I * A = A" << endl;
644
645 auto domain = make_shared<AlDomain<int>>();
646 for (int i = 0; i < 4; i++)
647 (void)domain->insert(i);
648
649 Matrix<int, int, double> A(domain, domain, {
650 {2, 3, 0, 0},
651 {0, 1, 4, 0},
652 {0, 0, 5, 6},
653 {7, 0, 0, 8}
654 });
655
656 cout << "\nMatrix A:" << endl;
657 cout << A.to_str() << endl;
658
659 auto I = A.identity();
660 cout << "\nIdentity matrix I:" << endl;
661 cout << I.to_str() << endl;
662
663 cout << "\nIdentity is sparse: only diagonal entries stored" << endl;
664}
665
666// =============================================================================
667// 11. Matrix-Vector Multiplication Methods
668// =============================================================================
669
671{
672 print_section("MATRIX-VECTOR MULTIPLICATION");
673
674 cout << "Multiple methods available for M * v:" << endl;
675 cout << " - Linear combination (default)" << endl;
676 cout << " - Dot product" << endl;
677 cout << " - Sparse iteration" << endl;
678
679 auto rows = make_shared<AlDomain<int>>();
680 auto cols = make_shared<AlDomain<int>>();
681 for (int i = 0; i < 3; i++)
682 {
683 (void)rows->insert(i);
684 (void)cols->insert(i);
685 }
686
687 Matrix<int, int, double> M(rows, cols, {
688 {1, 2, 3},
689 {4, 5, 6},
690 {7, 8, 9}
691 });
692
693 Vector<int, double> v(cols);
694 v.set_entry(0, 1);
695 v.set_entry(1, 0); // Sparse: only 2 non-zero entries
696 v.set_entry(2, 2);
697
698 cout << "\nMatrix M:" << endl;
699 cout << M.to_str() << endl;
700
701 cout << "\nVector v: (0:1, 2:2) -- note v[1]=0 not stored" << endl;
702
703 // Method 1: Linear combination (operator*)
704 auto r1 = M * v; // Uses mult_matrix_vector_linear_comb
705 cout << "\nM * v (linear combination):" << endl;
706 for (auto it = r1.get_it(); it.has_curr(); it.next())
707 {
708 auto e = it.get_curr();
709 cout << " [" << e.first << "] = " << e.second << endl;
710 }
711
712 // Method 2: Dot product
713 auto r2 = M.mult_matrix_vector_dot_product(v);
714 cout << "\nM * v (dot product):" << endl;
715 for (auto it = r2.get_it(); it.has_curr(); it.next())
716 {
717 auto e = it.get_curr();
718 cout << " [" << e.first << "] = " << e.second << endl;
719 }
720
721 // Method 3: Sparse iteration
722 auto r3 = M.mult_matrix_vector_sparse(v);
723 cout << "\nM * v (sparse):" << endl;
724 for (auto it = r3.get_it(); it.has_curr(); it.next())
725 {
726 auto e = it.get_curr();
727 cout << " [" << e.first << "] = " << e.second << endl;
728 }
729
730 cout << "\nAll methods produce same result (choose based on sparsity)" << endl;
731
732 // Vector * Matrix
733 print_subsection("Vector-Matrix Multiplication (v * M)");
734 Vector<int, double> u(rows);
735 u.set_entry(0, 1.5);
736 u.set_entry(2, 3);
737
738 cout << "\nVector u: (0:1.5, 2:3)" << endl;
739 auto r4 = u * M; // Uses mult_vector_matrix_linear_comb
740 cout << "\nu * M:" << endl;
741 for (auto it = r4.get_it(); it.has_curr(); it.next())
742 {
743 auto e = it.get_curr();
744 cout << " [" << e.first << "] = " << e.second << endl;
745 }
746}
747
748// =============================================================================
749// 12. Matrix-Matrix Multiplication
750// =============================================================================
751
753{
754 print_section("MATRIX-MATRIX MULTIPLICATION");
755
756 cout << "Two methods for A * B:" << endl;
757 cout << " - vector_matrix_mult: row_i * B for each row" << endl;
758 cout << " - matrix_vector_mult: A * col_j for each column" << endl;
759
760 // IMPORTANT: For multiplication A*B, column domain of A must be
761 // identical (same shared_ptr) to row domain of B
763 auto shared_domain = make_shared<AlDomain<int>>(); // shared between A cols and B rows
765
766 for (int i = 0; i < 2; i++)
767 (void)rowsA->insert(i);
768 for (int i = 0; i < 3; i++)
769 (void)shared_domain->insert(i);
770 for (int i = 0; i < 2; i++)
771 (void)colsB->insert(i);
772
773 // A is 2x3
775 {1, 2, 3},
776 {4, 5, 6}
777 });
778
779 // B is 3x2 (rows domain = A's column domain)
781 {7, 8},
782 {9, 10},
783 {11, 12}
784 });
785
786 cout << "\nMatrix A (2x3):" << endl;
787 cout << A.to_str() << endl;
788
789 cout << "\nMatrix B (3x2):" << endl;
790 cout << B.to_str() << endl;
791
792 // Method 1: vector_matrix_mult
793 auto C1 = A.vector_matrix_mult(B);
794 cout << "\nA * B (vector_matrix_mult):" << endl;
795 cout << C1.to_str() << endl;
796
797 // Method 2: matrix_vector_mult
798 auto C2 = A.matrix_vector_mult(B);
799 cout << "\nA * B (matrix_vector_mult):" << endl;
800 cout << C2.to_str() << endl;
801
802 cout << "\nBoth methods yield the same result" << endl;
803 cout << "Verified: C1 == C2 ? " << (C1 == C2 ? "YES" : "NO") << endl;
804}
805
806// =============================================================================
807// 13. Outer Product
808// =============================================================================
809
811{
812 print_section("OUTER PRODUCT");
813
814 cout << "The outer product of vectors u and v produces a matrix M" << endl;
815 cout << "where M[i][j] = u[i] * v[j]" << endl;
816
818 (void)dom_u->insert("x");
819 (void)dom_u->insert("y");
820 (void)dom_u->insert("z");
821
823 (void)dom_v->insert("a");
824 (void)dom_v->insert("b");
825
827 u.set_entry("x", 1);
828 u.set_entry("y", 2);
829 u.set_entry("z", 3);
830
832 v.set_entry("a", 4);
833 v.set_entry("b", 5);
834
835 cout << "\nVector u: x=1, y=2, z=3" << endl;
836 cout << "Vector v: a=4, b=5" << endl;
837
838 auto M = outer_product(u, v);
839 cout << "\nOuter product u ⊗ v:" << endl;
840 cout << M.to_str() << endl;
841
842 cout << "\nVerification:" << endl;
843 cout << " M[y][a] = u[y] * v[a] = 2 * 4 = " << M.get_entry("y", "a") << endl;
844 cout << " M[z][b] = u[z] * v[b] = 3 * 5 = " << M.get_entry("z", "b") << endl;
845}
846
847// =============================================================================
848// 14. Matrix Comparison
849// =============================================================================
850
852{
853 print_section("MATRIX COMPARISON");
854
855 cout << "Matrices can be compared with == and != operators" << endl;
856 cout << "Comparison uses epsilon tolerance for floating-point values" << endl;
857
858 auto domain = make_shared<AlDomain<int>>();
859 for (int i = 0; i < 2; i++)
860 (void)domain->insert(i);
861
862 Matrix<int, int, double> A(domain, domain, {
863 {1.0, 2.0},
864 {3.0, 4.0}
865 });
866
867 Matrix<int, int, double> B(domain, domain, {
868 {1.0, 2.0},
869 {3.0, 4.0}
870 });
871
872 Matrix<int, int, double> C(domain, domain, {
873 {1.0, 2.0},
874 {3.0, 4.001} // Slightly different
875 });
876
877 cout << "\nMatrix A:" << endl;
878 cout << A.to_str() << endl;
879
880 cout << "\nMatrix B (same as A):" << endl;
881 cout << B.to_str() << endl;
882
883 cout << "\nMatrix C (A[1][1] is 4.001):" << endl;
884 cout << C.to_str() << endl;
885
886 cout << "\nComparisons:" << endl;
887 cout << " A == B ? " << (A == B ? "YES" : "NO") << endl;
888 cout << " A == C ? " << (A == C ? "YES" : "NO") << endl;
889 cout << " A != C ? " << (A != C ? "YES" : "NO") << endl;
890
891 // Epsilon-sensitive comparison
892 print_subsection("Epsilon-Sensitive Comparison");
893 Matrix<int, int, double> D(domain, domain, {
894 {1.0, 2.0},
895 {3.0, 4.0 + 1e-8} // Within default epsilon (1e-7)
896 });
897
898 cout << "\nMatrix D has A[1][1] = 4.0 + 1e-8 (within epsilon=1e-7)" << endl;
899 cout << " A == D ? " << (A == D ? "YES" : "NO") << " (within epsilon tolerance)" << endl;
900}
901
902// =============================================================================
903// 15. Matrix Arithmetic Operations
904// =============================================================================
905
907{
908 print_section("MATRIX ARITHMETIC OPERATIONS");
909
910 cout << "Supported: addition (+, +=), subtraction (-, -=), scalar mult (*)" << endl;
911
912 auto domain = make_shared<AlDomain<int>>();
913 for (int i = 0; i < 2; i++)
914 (void)domain->insert(i);
915
916 Matrix<int, int, double> A(domain, domain, {
917 {1, 2},
918 {3, 4}
919 });
920
921 Matrix<int, int, double> B(domain, domain, {
922 {5, 6},
923 {7, 8}
924 });
925
926 cout << "\nMatrix A:" << endl;
927 cout << A.to_str() << endl;
928
929 cout << "\nMatrix B:" << endl;
930 cout << B.to_str() << endl;
931
932 // Addition
933 auto sum = A + B;
934 cout << "\nA + B:" << endl;
935 cout << sum.to_str() << endl;
936
937 // Subtraction
938 auto diff = A - B;
939 cout << "\nA - B:" << endl;
940 cout << diff.to_str() << endl;
941
942 // Scalar multiplication
943 auto scaled = 2.5 * A;
944 cout << "\n2.5 * A:" << endl;
945 cout << scaled.to_str() << endl;
946
947 // In-place modification
948 print_subsection("In-Place Operations");
950 C += B;
951 cout << "\nC = A; C += B:" << endl;
952 cout << C.to_str() << endl;
953
954 C.mult_by_scalar(0.5);
955 cout << "\nC.mult_by_scalar(0.5):" << endl;
956 cout << C.to_str() << endl;
957}
958
959// =============================================================================
960// 16. Row and Column Operations
961// =============================================================================
962
964{
965 print_section("ROW AND COLUMN OPERATIONS");
966
967 cout << "Methods for working with rows and columns:" << endl;
968 cout << " - get_row_vector(), get_col_vector()" << endl;
969 cout << " - set_vector_as_row(), set_vector_as_col()" << endl;
970 cout << " - to_rowlist(), to_collist()" << endl;
971 cout << " - get_row_as_list(), get_col_as_list()" << endl;
972
973 auto rows = make_shared<AlDomain<string>>();
974 auto cols = make_shared<AlDomain<string>>();
975 (void)rows->insert("A");
976 (void)rows->insert("B");
977 (void)cols->insert("X");
978 (void)cols->insert("Y");
979 (void)cols->insert("Z");
980
981 Matrix<string, string, double> M(rows, cols);
982 M.set_entry("A", "X", 1); M.set_entry("A", "Y", 2); M.set_entry("A", "Z", 3);
983 M.set_entry("B", "X", 4); M.set_entry("B", "Y", 5); M.set_entry("B", "Z", 6);
984
985 cout << "\nMatrix M:" << endl;
986 cout << M.to_str() << endl;
987
988 // Get row as vector
989 print_subsection("Get Row as Vector");
990 auto row_A = M.get_row_vector("A");
991 cout << "Row 'A' as vector:" << endl;
992 for (auto it = row_A.get_it(); it.has_curr(); it.next())
993 {
994 auto e = it.get_curr();
995 cout << " [" << e.first << "] = " << e.second << endl;
996 }
997
998 // Get column as vector
999 print_subsection("Get Column as Vector");
1000 auto col_Y = M.get_col_vector("Y");
1001 cout << "Column 'Y' as vector:" << endl;
1002 for (auto it = col_Y.get_it(); it.has_curr(); it.next())
1003 {
1004 auto e = it.get_curr();
1005 cout << " [" << e.first << "] = " << e.second << endl;
1006 }
1007
1008 // Set a row from vector
1009 print_subsection("Set Row from Vector");
1011 new_row.set_entry("X", 10);
1012 new_row.set_entry("Y", 20);
1013 new_row.set_entry("Z", 30);
1014
1015 M.set_vector_as_row("B", new_row);
1016 cout << "After setting row 'B' to (10, 20, 30):" << endl;
1017 cout << M.to_str() << endl;
1018
1019 // Convert to list of row vectors
1020 print_subsection("Convert to List of Rows");
1021 auto row_list = M.to_rowlist();
1022 cout << "Matrix as list of " << row_list.size() << " row vectors" << endl;
1023}
1024
1025// =============================================================================
1026// 17. Practical: Linear System Example
1027// =============================================================================
1028
1030{
1031 print_section("PRACTICAL: LINEAR EQUATIONS");
1032
1033 cout << "Using sparse matrices to represent linear systems" << endl;
1034 cout << "\nSystem: 2x + 3y = 13" << endl;
1035 cout << " 4x - y = 5" << endl;
1036 cout << "Solution: x=2, y=3" << endl;
1037
1039 (void)vars->insert("x");
1040 (void)vars->insert("y");
1041
1043 (void)eqs->insert("eq1");
1044 (void)eqs->insert("eq2");
1045
1046 // Coefficient matrix A
1048 A.set_entry("eq1", "x", 2); A.set_entry("eq1", "y", 3);
1049 A.set_entry("eq2", "x", 4); A.set_entry("eq2", "y", -1);
1050
1051 cout << "\nCoefficient matrix A:" << endl;
1052 cout << A.to_str() << endl;
1053
1054 // Solution vector
1055 Vector<string, double> solution(vars);
1056 solution.set_entry("x", 2);
1057 solution.set_entry("y", 3);
1058
1059 cout << "\nSolution vector: x=2, y=3" << endl;
1060
1061 // Verify: A * solution = b
1062 auto b = A * solution;
1063 cout << "\nVerification A * solution:" << endl;
1064 for (auto it = b.get_it(); it.has_curr(); it.next())
1065 {
1066 auto e = it.get_curr();
1067 cout << " " << e.first << " = " << e.second << endl;
1068 }
1069 cout << "\nExpected: eq1=13, eq2=5 ✓" << endl;
1070}
1071
1072// =============================================================================
1073// Main
1074// =============================================================================
1075
1076int main(int argc, char* argv[])
1077{
1078 try
1079 {
1080 TCLAP::CmdLine cmd(
1081 "Sparse Matrix and Vector example for Aleph-w.\n"
1082 "Demonstrates domain-based indexing and efficient sparse storage.",
1083 ' ', "1.0"
1084 );
1085
1086 cmd.parse(argc, argv);
1087
1088 cout << "\n";
1089 cout << "============================================================\n";
1090 cout << " ALEPH-W SPARSE MATRIX AND VECTOR EXAMPLE\n";
1091 cout << "============================================================\n";
1092
1099 demo_epsilon();
1102 demo_identity();
1110
1111 cout << "\n" << string(60, '=') << "\n";
1112 cout << "Sparse Matrix and Vector demo completed!\n";
1113 cout << string(60, '=') << "\n\n";
1114
1115 return 0;
1116 }
1117 catch (TCLAP::ArgException& e)
1118 {
1119 cerr << "Error: " << e.error() << " for argument " << e.argId() << endl;
1120 return 1;
1121 }
1122 catch (exception& e)
1123 {
1124 cerr << "Error: " << e.what() << endl;
1125 return 1;
1126 }
1127}
Functional programming utilities for Aleph-w containers.
int main()
void print_vec(const string &label, const vector< T > &v)
Integer domain classes for sparse data structures.
Sparse matrix with generic domains.
Sparse vector with named elements.
int num_nodes
Definition btreepic.C:410
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Sparse matrix with generic row and column domains.
Definition al-matrix.H:66
Vector< Tcol, NumType > get_row_vector(const Trow &row) const
Given a row, build a vector corresponding to the row.
Definition al-matrix.H:515
DynList< Vector< Tcol, NumType > > to_rowlist() const
Return a list of vectors corresponding to the rows.
Definition al-matrix.H:474
Matrix & mult_by_scalar(const NumType &scalar)
Multiply all entries by a scalar (in-place).
Definition al-matrix.H:808
NumType get_entry(const Trow &row, const Tcol &col)
Get an entry value (non-const version with lazy cleanup).
Definition al-matrix.H:366
Vector< Trow, NumType > get_col_vector(const Tcol &col) const
Given a column, build a vector corresponding to the column.
Definition al-matrix.H:530
std::string to_str() const
Convert matrix to a formatted string representation.
Definition al-matrix.H:875
Matrix transpose() const
Compute the transpose of this matrix.
Definition al-matrix.H:422
void set_entry(const Trow &row, const Tcol &col, const NumType &val)
Set an entry value.
Definition al-matrix.H:403
Matrix & set_vector_as_row(const Trow &row, const Vector< Tcol, NumType > &vec)
Set a row from a vector.
Definition al-matrix.H:691
Sparse vector implementation with domain-based indexing.
Definition al-vector.H:87
void set_entry(const T &i, const NumType &value)
Set a vector entry at given index.
Definition al-vector.H:268
const NumType & get_epsilon() const noexcept
Get the epsilon value used for zero comparisons.
Definition al-vector.H:119
Iterator get_it() const noexcept
Definition al-vector.H:700
void set_epsilon(const NumType &e) noexcept
Set the epsilon value for zero comparisons.
Definition al-vector.H:126
NumType get_entry(const T &i)
Get vector entry at given index (non-const version)
Definition al-vector.H:340
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Singly linked list implementations with head-tail access.
void print_subsection(const string &title)
void demo_vector_arithmetic()
void print_section(const string &title)
void demo_outer_product()
void demo_linear_system()
void demo_named_matrix()
void demo_epsilon()
void demo_string_indexed_vector()
void demo_adjacency_matrix()
void demo_comparison()
void demo_sparse_matrix()
void demo_matrix_mult()
void demo_identity()
void demo_matrix_vector_mult()
void demo_matrix_arithmetic()
void demo_initializer_list()
void demo_row_col_operations()
void demo_sparse_vector()
void demo_transpose()
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
Matrix< Trow, Tcol, NumType > outer_product(const Vector< Trow, NumType > &v1, const Vector< Tcol, NumType > &v2)
Compute the outer product of two vectors.
Definition al-matrix.H:1032
DynList< T > maps(const C &c, Op op)
Classic map operation.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
STL namespace.