File: distribute.cc

package info (click to toggle)
cadabra2 2.4.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 78,732 kB
  • sloc: ansic: 133,450; cpp: 92,064; python: 1,530; javascript: 203; sh: 184; xml: 182; objc: 53; makefile: 51
file content (129 lines) | stat: -rw-r--r-- 3,893 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

#include "distribute.hh"
#include "Cleanup.hh"

#include "properties/Distributable.hh"

#include "algorithms/flatten_product.hh"
#include "properties/Distributable.hh"

using namespace cadabra;

distribute::distribute(const Kernel& k, Ex& tr)
	: Algorithm(k, tr)
	{
	}

bool distribute::can_apply(iterator st)
	{
	//	std::cout << *st->name << std::endl;
	const Distributable *db=kernel.properties.get<Distributable>(st);
	if(!db) {
		return false;
		}

	sibling_iterator facs=tr.begin(st);
	while(facs!=tr.end(st)) {
		if(*(*facs).name=="\\sum" || *(*facs).name=="\\oplus")
			return true;
		//		if(*st->name=="\\indexbracket" || *st->name=="\\diff") break; // only first argument is object
		++facs;
		}
	return false;
	}

Algorithm::result_t distribute::apply(iterator& prod)
	{
	Ex rep;
	rep.set_head(str_node("\\sum", prod->fl.bracket, prod->fl.parent_rel));
	sibling_iterator top=rep.begin();
	// add
	iterator ploc=rep.append_child(top, str_node(prod->name, prod->fl.bracket, prod->fl.parent_rel));
	// The multiplier should sit on each term, not on the sum.
	ploc->multiplier=prod->multiplier;

	// Examine each child node in turn. If it is a sum, distribute it
	// over all previously constructed nodes. Otherwise, add the child
	// node as a child to the previously constructed nodes.

	// "facs" iterates over all child nodes of the distributable (top-level) node
	sibling_iterator facs=tr.begin(prod);
	while(facs!=tr.end(prod)) {
		std::string sumname=*(*facs).name;
		if(sumname=="\\sum" || sumname=="\\oplus") {
			sibling_iterator se=rep.begin(top);
			rep.begin()->name=facs->name;
			// "se" iterates over all nodes in the replacement \sum
			while(se!=rep.end(top)) {
				if(interrupted)
					throw InterruptionException();

				Ex termrep;
				termrep.set_head(str_node());
				sibling_iterator sumch=tr.begin(facs);
				while(sumch!=tr.end(facs)) {
					if(interrupted)
						throw InterruptionException();

					// add product "se" to termrep.
					sibling_iterator dup=termrep.append_child(termrep.begin(), str_node()); // dummy
					dup=termrep.replace(dup, se);
					// add term from sum as factor to product above.
					sibling_iterator newfact=termrep.append_child(dup, sumch);
					// put the multiplier up front
					multiply(dup->multiplier,*newfact->multiplier);
					multiply(dup->multiplier,*facs->multiplier);
					one(newfact->multiplier);
					// make this child inherit the bracket from the sum node
					newfact->fl.bracket=facs->fl.bracket;
					//					newfact->fl.bracket=str_node::b_none;
					++sumch;
					}
				sibling_iterator nxt=se;
				++nxt;
				sibling_iterator sep1=se;
				++sep1;
				se=rep.move_ontop(se, (sibling_iterator)(termrep.begin()));
				rep.flatten(se);
				rep.erase(se);
				//				rep.replace(se, sep1, termrep.begin(termrep.begin()), termrep.end(termrep.begin()));
				se=nxt;
				}
			}
		else {
			sibling_iterator se=rep.begin(top);
			while(se!=rep.end(top)) {
				if(interrupted)
					throw InterruptionException();
				rep.append_child(se, facs);
				++se;
				}
			}
		++facs;
		}
	if(rep.number_of_children(top)==1) { // nothing happened, no sum was present
		//		prod->fl.mark=0; // handled
		// std::cerr << "only one for " << Ex(prod) << std::endl;
		return result_t::l_no_action;
		}

	// FIXME: why does this faster move lead to a crash in linear.cdb?
	iterator ret=tr.move_ontop(prod, (iterator)top);

	// std::cerr << "cleaning up at " << Ex(ret) << std::endl;
	auto sib=tr.begin(ret);
	while(sib!=tr.end(ret)) {
		iterator ii=sib;
		++sib;
		cleanup_dispatch(kernel, tr, ii);
		}
	cleanup_dispatch(kernel, tr, ret);
	// std::cerr << "cleaned up at " << Ex(ret) << std::endl;


	// FIXME: if we had a flattened sum, does the apply_recursive now
	// go and examine every sum that we have created? Should we better
	// return an iterator to the last element in the sum?
	prod=ret;
	return result_t::l_applied;
	}