deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
linear_operator.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2015 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_linear_operator_h
14#define dealii_linear_operator_h
15
16#include <deal.II/base/config.h>
17
19
21
22#include <array>
23#include <functional>
24#include <type_traits>
25
27
28// Forward declarations:
29#ifndef DOXYGEN
30namespace internal
31{
32 namespace LinearOperatorImplementation
33 {
34 class EmptyPayload;
35 }
36} // namespace internal
37
38template <typename Number>
39class Vector;
40
42
43template <typename Range = Vector<double>,
44 typename Domain = Range,
45 typename Payload =
46 internal::LinearOperatorImplementation::EmptyPayload>
47class LinearOperator;
48#endif
49
50template <
51 typename Range = Vector<double>,
52 typename Domain = Range,
54 typename OperatorExemplar,
55 typename Matrix>
57linear_operator(const OperatorExemplar &, const Matrix &);
58
59template <
60 typename Range = Vector<double>,
61 typename Domain = Range,
63 typename Matrix>
65linear_operator(const Matrix &);
66
67template <
68 typename Range = Vector<double>,
69 typename Domain = Range,
73
74template <typename Range, typename Domain, typename Payload>
77
78
197template <typename Range, typename Domain, typename Payload>
198class LinearOperator : public Payload
199{
200public:
209 LinearOperator(const Payload &payload = Payload())
210 : Payload(payload)
211 , is_null_operator(false)
212 {
213 vmult = [](Range &, const Domain &) {
214 Assert(false,
215 ExcMessage("Uninitialized LinearOperator<Range, "
216 "Domain>::vmult called"));
217 };
218
219 vmult_add = [](Range &, const Domain &) {
220 Assert(false,
221 ExcMessage("Uninitialized LinearOperator<Range, "
222 "Domain>::vmult_add called"));
223 };
224
225 Tvmult = [](Domain &, const Range &) {
226 Assert(false,
227 ExcMessage("Uninitialized LinearOperator<Range, "
228 "Domain>::Tvmult called"));
229 };
230
231 Tvmult_add = [](Domain &, const Range &) {
232 Assert(false,
233 ExcMessage("Uninitialized LinearOperator<Range, "
234 "Domain>::Tvmult_add called"));
235 };
236
237 reinit_range_vector = [](Range &, bool) {
238 Assert(false,
239 ExcMessage("Uninitialized LinearOperator<Range, "
240 "Domain>::reinit_range_vector method called"));
241 };
242
243 reinit_domain_vector = [](Domain &, bool) {
244 Assert(false,
245 ExcMessage("Uninitialized LinearOperator<Range, "
246 "Domain>::reinit_domain_vector method called"));
247 };
248 }
249
254
260 template <typename Op,
261 typename = std::enable_if_t<
262 !std::is_base_of_v<LinearOperator<Range, Domain, Payload>, Op>>>
263 LinearOperator(const Op &op)
264 {
265 *this = linear_operator<Range, Domain, Payload, Op>(op);
266 }
267
273
278 template <typename Op,
279 typename = std::enable_if_t<
280 !std::is_base_of_v<LinearOperator<Range, Domain, Payload>, Op>>>
282 operator=(const Op &op)
283 {
284 *this = linear_operator<Range, Domain, Payload, Op>(op);
285 return *this;
286 }
287
292 std::function<void(Range &v, const Domain &u)> vmult;
293
298 std::function<void(Range &v, const Domain &u)> vmult_add;
299
304 std::function<void(Domain &v, const Range &u)> Tvmult;
305
310 std::function<void(Domain &v, const Range &u)> Tvmult_add;
311
319 std::function<void(Range &v, bool omit_zeroing_entries)> reinit_range_vector;
320
328 std::function<void(Domain &v, bool omit_zeroing_entries)>
330
342 {
343 *this = *this + second_op;
344 return *this;
345 }
346
353 {
354 *this = *this - second_op;
355 return *this;
356 }
357
364 {
365 *this = *this * second_op;
366 return *this;
367 }
368
374 operator*=(typename Domain::value_type number)
375 {
376 *this = *this * number;
377 return *this;
378 }
379
386
388};
389
390
405template <typename Range, typename Domain, typename Payload>
409{
410 if (first_op.is_null_operator)
411 {
412 return second_op;
413 }
414 else if (second_op.is_null_operator)
415 {
416 return first_op;
417 }
418 else
419 {
421 static_cast<const Payload &>(first_op) +
422 static_cast<const Payload &>(second_op)};
423
424 return_op.reinit_range_vector = first_op.reinit_range_vector;
425 return_op.reinit_domain_vector = first_op.reinit_domain_vector;
426
427 // ensure to have valid computation objects by catching first_op and
428 // second_op by value
429
430 return_op.vmult = [first_op, second_op](Range &v, const Domain &u) {
431 first_op.vmult(v, u);
432 second_op.vmult_add(v, u);
433 };
434
435 return_op.vmult_add = [first_op, second_op](Range &v, const Domain &u) {
436 first_op.vmult_add(v, u);
437 second_op.vmult_add(v, u);
438 };
439
440 return_op.Tvmult = [first_op, second_op](Domain &v, const Range &u) {
441 second_op.Tvmult(v, u);
442 first_op.Tvmult_add(v, u);
443 };
444
445 return_op.Tvmult_add = [first_op, second_op](Domain &v, const Range &u) {
446 second_op.Tvmult_add(v, u);
447 first_op.Tvmult_add(v, u);
448 };
449
450 return return_op;
451 }
452}
453
454
464template <typename Range, typename Domain, typename Payload>
468{
469 if (first_op.is_null_operator)
470 {
471 return -1. * second_op;
472 }
473 else if (second_op.is_null_operator)
474 {
475 return first_op;
476 }
477 else
478 {
479 // implement with addition and scalar multiplication
480 return first_op + (-1. * second_op);
481 }
482}
483
484
502template <typename Range, typename Domain, typename Payload>
504operator*(typename Range::value_type number,
506{
507 static_assert(
508 std::is_convertible_v<typename Range::value_type,
509 typename Domain::value_type>,
510 "Range and Domain must have implicitly convertible 'value_type's");
511
512 if (op.is_null_operator)
513 {
514 return op;
515 }
516 else if (number == 0.)
517 {
518 return null_operator(op);
519 }
520 else
521 {
523
524 // ensure to have valid computation objects by catching number and op by
525 // value
526
527 return_op.vmult = [number, op](Range &v, const Domain &u) {
528 op.vmult(v, u);
529 v *= number;
530 };
531
532 return_op.vmult_add = [number, op](Range &v, const Domain &u) {
533 v /= number;
534 op.vmult_add(v, u);
535 v *= number;
536 };
537
538 return_op.Tvmult = [number, op](Domain &v, const Range &u) {
539 op.Tvmult(v, u);
540 v *= number;
541 };
542
543 return_op.Tvmult_add = [number, op](Domain &v, const Range &u) {
544 v /= number;
545 op.Tvmult_add(v, u);
546 v *= number;
547 };
548
549 return return_op;
550 }
551}
552
553
569template <typename Range, typename Domain, typename Payload>
572 typename Domain::value_type number)
573{
574 static_assert(
575 std::is_convertible_v<typename Range::value_type,
576 typename Domain::value_type>,
577 "Range and Domain must have implicitly convertible 'value_type's");
578
579 return number * op;
580}
581
599template <typename Range,
600 typename Intermediate,
601 typename Domain,
602 typename Payload>
606{
607 if (first_op.is_null_operator || second_op.is_null_operator)
608 {
610 return_op.reinit_domain_vector = second_op.reinit_domain_vector;
611 return_op.reinit_range_vector = first_op.reinit_range_vector;
612 return null_operator(return_op);
613 }
614 else
615 {
617 static_cast<const Payload &>(first_op) *
618 static_cast<const Payload &>(second_op)};
619
620 return_op.reinit_domain_vector = second_op.reinit_domain_vector;
621 return_op.reinit_range_vector = first_op.reinit_range_vector;
622
623 // ensure to have valid computation objects by catching first_op and
624 // second_op by value
625
626 return_op.vmult = [first_op, second_op](Range &v, const Domain &u) {
628
629 typename VectorMemory<Intermediate>::Pointer i(vector_memory);
630 second_op.reinit_range_vector(*i, /*bool omit_zeroing_entries =*/true);
631 second_op.vmult(*i, u);
632 first_op.vmult(v, *i);
633 };
634
635 return_op.vmult_add = [first_op, second_op](Range &v, const Domain &u) {
637
638 typename VectorMemory<Intermediate>::Pointer i(vector_memory);
639 second_op.reinit_range_vector(*i, /*bool omit_zeroing_entries =*/true);
640 second_op.vmult(*i, u);
641 first_op.vmult_add(v, *i);
642 };
643
644 return_op.Tvmult = [first_op, second_op](Domain &v, const Range &u) {
646
647 typename VectorMemory<Intermediate>::Pointer i(vector_memory);
648 first_op.reinit_domain_vector(*i, /*bool omit_zeroing_entries =*/true);
649 first_op.Tvmult(*i, u);
650 second_op.Tvmult(v, *i);
651 };
652
653 return_op.Tvmult_add = [first_op, second_op](Domain &v, const Range &u) {
655
656 typename VectorMemory<Intermediate>::Pointer i(vector_memory);
657 first_op.reinit_domain_vector(*i, /*bool omit_zeroing_entries =*/true);
658 first_op.Tvmult(*i, u);
659 second_op.Tvmult_add(v, *i);
660 };
661
662 return return_op;
663 }
664}
665
666
675template <typename Range, typename Domain, typename Payload>
678{
679 LinearOperator<Domain, Range, Payload> return_op{op.transpose_payload()};
680
682 return_op.reinit_domain_vector = op.reinit_range_vector;
683
684 return_op.vmult = op.Tvmult;
685 return_op.vmult_add = op.Tvmult_add;
686 return_op.Tvmult = op.vmult;
687 return_op.Tvmult_add = op.vmult_add;
688
689 return return_op;
690}
691
692
712template <typename Payload,
713 typename Solver,
714 typename Preconditioner,
715 typename Range = typename Solver::vector_type,
716 typename Domain = Range>
719 Solver &solver,
720 const Preconditioner &preconditioner)
721{
723 op.inverse_payload(solver, preconditioner)};
724
726 return_op.reinit_domain_vector = op.reinit_range_vector;
727
728 return_op.vmult = [op, &solver, &preconditioner](Range &v, const Domain &u) {
729 op.reinit_range_vector(v, /*bool omit_zeroing_entries =*/false);
730 solver.solve(op, v, u, preconditioner);
731 };
732
733 return_op.vmult_add = [op, &solver, &preconditioner](Range &v,
734 const Domain &u) {
735 GrowingVectorMemory<Range> vector_memory;
736
737 typename VectorMemory<Range>::Pointer v2(vector_memory);
738 op.reinit_range_vector(*v2, /*bool omit_zeroing_entries =*/false);
739 solver.solve(op, *v2, u, preconditioner);
740 v += *v2;
741 };
742
743 return_op.Tvmult = [op, &solver, &preconditioner](Range &v, const Domain &u) {
744 op.reinit_range_vector(v, /*bool omit_zeroing_entries =*/false);
745 solver.solve(transpose_operator(op), v, u, preconditioner);
746 };
747
748 return_op.Tvmult_add = [op, &solver, &preconditioner](Range &v,
749 const Domain &u) {
750 GrowingVectorMemory<Range> vector_memory;
751
752 typename VectorMemory<Range>::Pointer v2(vector_memory);
753 op.reinit_range_vector(*v2, /*bool omit_zeroing_entries =*/false);
754 solver.solve(transpose_operator(op), *v2, u, preconditioner);
755 v += *v2;
756 };
757
758 return return_op;
759}
760
761
770template <typename Payload,
771 typename Solver,
772 typename Range = typename Solver::vector_type,
773 typename Domain = Range>
776 Solver &solver,
777 const LinearOperator<Range, Domain, Payload> &preconditioner)
778{
780 op.inverse_payload(solver, preconditioner)};
781
783 return_op.reinit_domain_vector = op.reinit_range_vector;
784
785 return_op.vmult = [op, &solver, preconditioner](Range &v, const Domain &u) {
786 op.reinit_range_vector(v, /*bool omit_zeroing_entries =*/false);
787 solver.solve(op, v, u, preconditioner);
788 };
789
790 return_op.vmult_add = [op, &solver, preconditioner](Range &v,
791 const Domain &u) {
792 GrowingVectorMemory<Range> vector_memory;
793
794 typename VectorMemory<Range>::Pointer v2(vector_memory);
795 op.reinit_range_vector(*v2, /*bool omit_zeroing_entries =*/false);
796 solver.solve(op, *v2, u, preconditioner);
797 v += *v2;
798 };
799
800 return_op.Tvmult = [op, &solver, preconditioner](Range &v, const Domain &u) {
801 op.reinit_range_vector(v, /*bool omit_zeroing_entries =*/false);
802 solver.solve(transpose_operator(op), v, u, preconditioner);
803 };
804
805 return_op.Tvmult_add = [op, &solver, preconditioner](Range &v,
806 const Domain &u) {
807 GrowingVectorMemory<Range> vector_memory;
808
809 typename VectorMemory<Range>::Pointer v2(vector_memory);
810 op.reinit_range_vector(*v2, /*bool omit_zeroing_entries =*/false);
811 solver.solve(transpose_operator(op), *v2, u, preconditioner);
812 v += *v2;
813 };
814
815 return return_op;
816}
817
818
828template <typename Payload,
829 typename Solver,
830 typename Range = typename Solver::vector_type,
831 typename Domain = Range>
834 Solver &solver)
835{
836 return inverse_operator(op, solver, identity_operator(op));
837}
838
839
848template <typename Payload,
849 typename Solver,
850 typename Range = typename Solver::vector_type,
851 typename Domain = Range>
854 Solver &solver,
855 const PreconditionIdentity &)
856{
857 return inverse_operator(op, solver);
858}
859
879template <
880 typename Range,
883identity_operator(const std::function<void(Range &, bool)> &reinit_vector)
884{
885 LinearOperator<Range, Range, Payload> return_op{Payload()};
886
887 return_op.reinit_range_vector = reinit_vector;
888 return_op.reinit_domain_vector = reinit_vector;
889
890 return_op.vmult = [](Range &v, const Range &u) { v = u; };
891
892 return_op.vmult_add = [](Range &v, const Range &u) { v += u; };
893
894 return_op.Tvmult = [](Range &v, const Range &u) { v = u; };
895
896 return_op.Tvmult_add = [](Range &v, const Range &u) { v += u; };
897
898 return return_op;
899}
900
901
914template <typename Range, typename Domain, typename Payload>
917{
918 auto return_op = identity_operator<Range, Payload>(op.reinit_range_vector);
919 static_cast<Payload &>(return_op) = op.identity_payload();
920
921 return return_op;
922}
923
924
934template <typename Range, typename Domain, typename Payload>
937{
938 LinearOperator<Range, Domain, Payload> return_op{op.null_payload()};
939
940 return_op.is_null_operator = true;
941
942 return_op.reinit_range_vector = op.reinit_range_vector;
943 return_op.reinit_domain_vector = op.reinit_domain_vector;
944
945 return_op.vmult = [](Range &v, const Domain &) { v = 0.; };
946
947 return_op.vmult_add = [](Range &, const Domain &) {};
948
949 return_op.Tvmult = [](Domain &v, const Range &) { v = 0.; };
950
951 return_op.Tvmult_add = [](Domain &, const Range &) {};
952
953 return return_op;
954}
955
966template <typename Range,
967 typename Domain,
968 typename Payload,
969 typename VectorType>
972 const VectorType &diagonal)
973{
975 return_op.reinit_range_vector = exemplar.reinit_range_vector;
976 return_op.reinit_domain_vector = exemplar.reinit_domain_vector;
977
978 return_op.vmult = [&diagonal](Range &dst, const Domain &src) {
979 Assert(src.size() == diagonal.size(),
980 ExcDimensionMismatch(src.size(), diagonal.size()));
981 Assert(dst.size() == diagonal.size(),
982 ExcDimensionMismatch(dst.size(), diagonal.size()));
983 dst = src;
984 dst.scale(diagonal);
985 };
986
987 return_op.vmult_add = [&diagonal](Range &dst, const Domain &src) {
988 Assert(src.size() == diagonal.size(),
989 ExcDimensionMismatch(src.size(), diagonal.size()));
990 Assert(dst.size() == diagonal.size(),
991 ExcDimensionMismatch(dst.size(), diagonal.size()));
992 Range tmp;
993 tmp = src;
994 tmp.scale(diagonal);
995 dst += tmp;
996 };
997
998 return_op.Tvmult = [&diagonal](Domain &dst, const Range &src) {
999 Assert(src.size() == diagonal.size(),
1000 ExcDimensionMismatch(src.size(), diagonal.size()));
1001 Assert(dst.size() == diagonal.size(),
1002 ExcDimensionMismatch(dst.size(), diagonal.size()));
1003 dst = src;
1004 dst.scale(diagonal);
1005 };
1006
1007 return_op.Tvmult_add = [&diagonal](Domain &dst, const Range &src) {
1008 Assert(src.size() == diagonal.size(),
1009 ExcDimensionMismatch(src.size(), diagonal.size()));
1010 Assert(dst.size() == diagonal.size(),
1011 ExcDimensionMismatch(dst.size(), diagonal.size()));
1012 Domain tmp;
1013 tmp = src;
1014 tmp.scale(diagonal);
1015 dst += tmp;
1016 };
1017 return return_op;
1018}
1019
1020
1021
1034template <
1035 typename Range,
1038mean_value_filter(const std::function<void(Range &, bool)> &reinit_vector)
1039{
1040 LinearOperator<Range, Range, Payload> return_op{Payload()};
1041
1042 return_op.reinit_range_vector = reinit_vector;
1043 return_op.reinit_domain_vector = reinit_vector;
1044
1045 return_op.vmult = [](Range &v, const Range &u) {
1046 const auto mean = u.mean_value();
1047
1048 v = u;
1049 v.add(-mean);
1050 };
1051
1052 return_op.vmult_add = [](Range &v, const Range &u) {
1053 const auto mean = u.mean_value();
1054
1055 v += u;
1056 v.add(-mean);
1057 };
1058
1059 return_op.Tvmult = return_op.vmult_add;
1060 return_op.Tvmult_add = return_op.vmult_add;
1061
1062 return return_op;
1063}
1064
1065
1078template <typename Range, typename Domain, typename Payload>
1081{
1082 auto return_op = mean_value_filter<Range, Payload>(op.reinit_range_vector);
1083 static_cast<Payload &>(return_op) = op.identity_payload();
1084
1085 return return_op;
1086}
1087
1088
1089namespace internal
1090{
1091 namespace LinearOperatorImplementation
1092 {
1104 template <typename Vector>
1106 {
1107 public:
1119 template <typename Matrix>
1120 static void
1121 reinit_range_vector(const Matrix &matrix,
1122 Vector &v,
1123 bool omit_zeroing_entries)
1124 {
1125 v.reinit(matrix.m(), omit_zeroing_entries);
1126 }
1127
1139 template <typename Matrix>
1140 static void
1141 reinit_domain_vector(const Matrix &matrix,
1142 Vector &v,
1143 bool omit_zeroing_entries)
1144 {
1145 v.reinit(matrix.n(), omit_zeroing_entries);
1146 }
1147 };
1148
1149
1162 {
1163 public:
1171 template <typename... Args>
1172 EmptyPayload(const Args &...)
1173 {}
1174
1175
1181 {
1182 return *this;
1183 }
1184
1185
1191 {
1192 return *this;
1193 }
1194
1195
1201 {
1202 return *this;
1203 }
1204
1205
1209 template <typename Solver, typename Preconditioner>
1211 inverse_payload(Solver &, const Preconditioner &) const
1212 {
1213 return *this;
1214 }
1215 };
1216
1221 inline EmptyPayload
1223 {
1224 return {};
1225 }
1226
1231 inline EmptyPayload
1233 {
1234 return {};
1235 }
1236
1237
1238
1239 // A trait class that determines whether type T provides public
1240 // (templated or non-templated) vmult_add member functions
1241 template <typename Range, typename Domain, typename T>
1243 {
1244 template <typename C>
1245 static std::false_type
1246 test(...);
1247
1248 template <typename C>
1249 static auto
1250 test(Range *r, Domain *d)
1251 -> decltype(std::declval<C>().vmult_add(*r, *d),
1252 std::declval<C>().Tvmult_add(*d, *r),
1253 std::true_type());
1254
1255 public:
1256 // type is std::true_type if Matrix provides vmult_add and Tvmult_add,
1257 // otherwise it is std::false_type
1258
1259 using type = decltype(test<T>(nullptr, nullptr));
1260 };
1261
1262
1263 // A helper function to apply a given vmult, or Tvmult to a vector with
1264 // intermediate storage
1265 template <typename Function, typename Range, typename Domain>
1266 void
1268 Range &v,
1269 const Domain &u,
1270 bool add)
1271 {
1272 GrowingVectorMemory<Range> vector_memory;
1273
1274 typename VectorMemory<Range>::Pointer i(vector_memory);
1275 i->reinit(v, /*bool omit_zeroing_entries =*/true);
1276
1277 function(*i, u);
1278
1279 if (add)
1280 v += *i;
1281 else
1282 v = *i;
1283 }
1284
1285
1286 // A helper class to add a reduced matrix interface to a LinearOperator
1287 // (typically provided by Preconditioner classes)
1288 template <typename Range, typename Domain, typename Payload>
1290 {
1291 public:
1292 template <typename Matrix>
1293 void
1295 const Matrix &matrix)
1296 {
1297 op.vmult = [&matrix](Range &v, const Domain &u) {
1298 if (PointerComparison::equal(&v, &u))
1299 {
1300 // If v and u are the same memory location use intermediate
1301 // storage
1303 [&matrix](Range &b, const Domain &a) { matrix.vmult(b, a); },
1304 v,
1305 u,
1306 /*bool add =*/false);
1307 }
1308 else
1309 {
1310 matrix.vmult(v, u);
1311 }
1312 };
1313
1314 op.vmult_add = [&matrix](Range &v, const Domain &u) {
1315 // use intermediate storage to implement vmult_add with vmult
1317 [&matrix](Range &b, const Domain &a) { matrix.vmult(b, a); },
1318 v,
1319 u,
1320 /*bool add =*/true);
1321 };
1322
1323 op.Tvmult = [&matrix](Domain &v, const Range &u) {
1324 if (PointerComparison::equal(&v, &u))
1325 {
1326 // If v and u are the same memory location use intermediate
1327 // storage
1329 [&matrix](Domain &b, const Range &a) { matrix.Tvmult(b, a); },
1330 v,
1331 u,
1332 /*bool add =*/false);
1333 }
1334 else
1335 {
1336 matrix.Tvmult(v, u);
1337 }
1338 };
1339
1340 op.Tvmult_add = [&matrix](Domain &v, const Range &u) {
1341 // use intermediate storage to implement Tvmult_add with Tvmult
1343 [&matrix](Domain &b, const Range &a) { matrix.Tvmult(b, a); },
1344 v,
1345 u,
1346 /*bool add =*/true);
1347 };
1348 }
1349 };
1350
1351
1352 // A helper class to add the full matrix interface to a LinearOperator
1353 template <typename Range, typename Domain, typename Payload>
1355 {
1356 public:
1357 template <typename Matrix>
1358 void
1360 const Matrix &matrix)
1361 {
1362 // As above ...
1363
1365 op, matrix);
1366
1367 // ... but add native vmult_add and Tvmult_add variants:
1368
1369 op.vmult_add = [&matrix](Range &v, const Domain &u) {
1370 if (PointerComparison::equal(&v, &u))
1371 {
1373 [&matrix](Range &b, const Domain &a) { matrix.vmult(b, a); },
1374 v,
1375 u,
1376 /*bool add =*/true);
1377 }
1378 else
1379 {
1380 matrix.vmult_add(v, u);
1381 }
1382 };
1383
1384 op.Tvmult_add = [&matrix](Domain &v, const Range &u) {
1385 if (PointerComparison::equal(&v, &u))
1386 {
1388 [&matrix](Domain &b, const Range &a) { matrix.Tvmult(b, a); },
1389 v,
1390 u,
1391 /*bool add =*/true);
1392 }
1393 else
1394 {
1395 matrix.Tvmult_add(v, u);
1396 }
1397 };
1398 }
1399 };
1400 } // namespace LinearOperatorImplementation
1401} // namespace internal
1402
1403
1460template <typename Range, typename Domain, typename Payload, typename Matrix>
1462linear_operator(const Matrix &matrix)
1463{
1464 // implement with the more generic variant below...
1465 return linear_operator<Range, Domain, Payload, Matrix, Matrix>(matrix,
1466 matrix);
1467}
1468
1469
1484template <typename Range,
1485 typename Domain,
1486 typename Payload,
1487 typename OperatorExemplar,
1488 typename Matrix>
1490linear_operator(const OperatorExemplar &operator_exemplar, const Matrix &matrix)
1491{
1493 // Initialize the payload based on the input exemplar matrix
1495 Payload(operator_exemplar, matrix)};
1496
1497 // Always store a reference to matrix and operator_exemplar in the lambda
1498 // functions. This ensures that a modification of the matrix after the
1499 // creation of a LinearOperator wrapper is respected - further a matrix
1500 // or an operator_exemplar cannot usually be copied...
1501
1502 return_op.reinit_range_vector =
1503 [&operator_exemplar](Range &v, bool omit_zeroing_entries) {
1505 Range>::reinit_range_vector(operator_exemplar, v, omit_zeroing_entries);
1506 };
1507
1508 return_op.reinit_domain_vector = [&operator_exemplar](
1509 Domain &v, bool omit_zeroing_entries) {
1511 Domain>::reinit_domain_vector(operator_exemplar, v, omit_zeroing_entries);
1512 };
1513
1514 std::conditional_t<
1518 .
1519 operator()(return_op, matrix);
1520
1521 return return_op;
1522}
1523
1524
1525
1542template <typename Range, typename Domain, typename Payload, typename Matrix>
1545 const Matrix &matrix)
1546{
1548 // Initialize the payload based on the LinearOperator exemplar
1549 auto return_op = operator_exemplar;
1550
1551 std::conditional_t<
1555 .
1556 operator()(return_op, matrix);
1557
1558 return return_op;
1559}
1560
1561
1564#ifndef DOXYGEN
1565
1566//
1567// Ensure that we never capture a reference to a temporary by accident.
1568// to avoid "stack use after free".
1569//
1570
1571template <
1572 typename Range = Vector<double>,
1573 typename Domain = Range,
1575 typename OperatorExemplar,
1576 typename Matrix,
1577 typename = std::enable_if_t<!std::is_lvalue_reference_v<Matrix>>>
1579linear_operator(const OperatorExemplar &, Matrix &&) = delete;
1580
1581template <
1582 typename Range = Vector<double>,
1583 typename Domain = Range,
1585 typename OperatorExemplar,
1586 typename Matrix,
1587 typename = std::enable_if_t<!std::is_lvalue_reference_v<OperatorExemplar>>,
1588 typename = std::enable_if_t<
1589 !std::is_same_v<OperatorExemplar, LinearOperator<Range, Domain, Payload>>>>
1591linear_operator(OperatorExemplar &&, const Matrix &) = delete;
1592
1593template <
1594 typename Range = Vector<double>,
1595 typename Domain = Range,
1597 typename OperatorExemplar,
1598 typename Matrix,
1599 typename = std::enable_if_t<!std::is_lvalue_reference_v<Matrix>>,
1600 typename = std::enable_if_t<!std::is_lvalue_reference_v<OperatorExemplar>>,
1601 typename = std::enable_if_t<
1602 !std::is_same_v<OperatorExemplar, LinearOperator<Range, Domain, Payload>>>>
1604linear_operator(OperatorExemplar &&, Matrix &&) = delete;
1605
1606template <
1607 typename Range = Vector<double>,
1608 typename Domain = Range,
1610 typename Matrix,
1611 typename = std::enable_if_t<!std::is_lvalue_reference_v<Matrix>>>
1614 Matrix &&) = delete;
1615
1616template <
1617 typename Range = Vector<double>,
1618 typename Domain = Range,
1620 typename Matrix,
1621 typename = std::enable_if_t<!std::is_lvalue_reference_v<Matrix>>>
1623linear_operator(Matrix &&) = delete;
1624
1625template <
1626 typename Payload,
1627 typename Solver,
1628 typename Preconditioner,
1629 typename Range = typename Solver::vector_type,
1630 typename Domain = Range,
1631 typename = std::enable_if_t<!std::is_lvalue_reference_v<Preconditioner>>,
1632 typename =
1633 std::enable_if_t<!std::is_same_v<Preconditioner, PreconditionIdentity>>,
1634 typename = std::enable_if_t<
1635 !std::is_same_v<Preconditioner, LinearOperator<Range, Domain, Payload>>>>
1638 Solver &,
1639 Preconditioner &&) = delete;
1640
1641#endif // DOXYGEN
1642
1644
1645#endif
*  *  reference operator*() const
LinearOperator< Range, Domain, Payload > operator*=(typename Domain::value_type number)
LinearOperator< Range, Domain, Payload > & operator=(const LinearOperator< Range, Domain, Payload > &)=default
std::function< void(Range &v, const Domain &u)> vmult_add
LinearOperator< Range, Domain, Payload > & operator=(const Op &op)
std::function< void(Domain &v, const Range &u)> Tvmult
std::function< void(Domain &v, bool omit_zeroing_entries)> reinit_domain_vector
LinearOperator(const Payload &payload=Payload())
std::function< void(Range &v, const Domain &u)> vmult
std::function< void(Range &v, bool omit_zeroing_entries)> reinit_range_vector
LinearOperator< Range, Domain, Payload > & operator+=(const LinearOperator< Range, Domain, Payload > &second_op)
std::function< void(Domain &v, const Range &u)> Tvmult_add
LinearOperator(const Op &op)
LinearOperator< Range, Domain, Payload > & operator*=(const LinearOperator< Domain, Domain, Payload > &second_op)
LinearOperator(const LinearOperator< Range, Domain, Payload > &)=default
LinearOperator< Range, Domain, Payload > & operator-=(const LinearOperator< Range, Domain, Payload > &second_op)
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
EmptyPayload inverse_payload(Solver &, const Preconditioner &) const
void operator()(LinearOperator< Range, Domain, Payload > &op, const Matrix &matrix)
void operator()(LinearOperator< Range, Domain, Payload > &op, const Matrix &matrix)
static void reinit_domain_vector(const Matrix &matrix, Vector &v, bool omit_zeroing_entries)
static void reinit_range_vector(const Matrix &matrix, Vector &v, bool omit_zeroing_entries)
static auto test(Range *r, Domain *d) -> decltype(std::declval< C >().vmult_add(*r, *d), std::declval< C >().Tvmult_add(*d, *r), std::true_type())
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver)
LinearOperator< Range, Domain, Payload > operator*(const LinearOperator< Range, Intermediate, Payload > &first_op, const LinearOperator< Intermediate, Domain, Payload > &second_op)
LinearOperator< Range, Domain, Payload > linear_operator(const OperatorExemplar &operator_exemplar, const Matrix &matrix)
LinearOperator< Range, Domain, Payload > operator-(const LinearOperator< Range, Domain, Payload > &first_op, const LinearOperator< Range, Domain, Payload > &second_op)
LinearOperator< Range, Range, Payload > identity_operator(const std::function< void(Range &, bool)> &reinit_vector)
LinearOperator< Range, Domain, Payload > null_operator(const LinearOperator< Range, Domain, Payload > &op)
LinearOperator< Range, Domain, Payload > identity_operator(const LinearOperator< Range, Domain, Payload > &op)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver, const PreconditionIdentity &)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver, const LinearOperator< Range, Domain, Payload > &preconditioner)
LinearOperator< Range, Domain, Payload > linear_operator(const OperatorExemplar &, const Matrix &)
LinearOperator< Range, Domain, Payload > null_operator(const LinearOperator< Range, Domain, Payload > &)
LinearOperator< Range, Domain, Payload > linear_operator(const Matrix &matrix)
LinearOperator< Domain, Range, Payload > transpose_operator(const LinearOperator< Range, Domain, Payload > &op)
LinearOperator< Range, Domain, Payload > mean_value_filter(const LinearOperator< Range, Domain, Payload > &op)
LinearOperator< Range, Domain, Payload > operator*(typename Range::value_type number, const LinearOperator< Range, Domain, Payload > &op)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver, const Preconditioner &preconditioner)
LinearOperator< Range, Domain, Payload > operator*(const LinearOperator< Range, Domain, Payload > &op, typename Domain::value_type number)
LinearOperator< Range, Domain, Payload > linear_operator(const LinearOperator< Range, Domain, Payload > &operator_exemplar, const Matrix &matrix)
LinearOperator< Range, Domain, Payload > diagonal_operator(const LinearOperator< Range, Domain, Payload > &exemplar, const VectorType &diagonal)
LinearOperator< Range, Range, Payload > mean_value_filter(const std::function< void(Range &, bool)> &reinit_vector)
LinearOperator< Range, Domain, Payload > identity_operator(const LinearOperator< Range, Domain, Payload > &)
LinearOperator< Range, Domain, Payload > operator+(const LinearOperator< Range, Domain, Payload > &first_op, const LinearOperator< Range, Domain, Payload > &second_op)
EmptyPayload operator+(const EmptyPayload &, const EmptyPayload &)
void apply_with_intermediate_storage(Function function, Range &v, const Domain &u, bool add)
static bool equal(const T *p1, const T *p2)