Related
I am trying to write a program that simplifies mathematical expressions.
I have already written a parser that converts a string to a binary tree.
For example (1+2)*x will become
*
/ \
+ x
/ \
1 2
The idea I had of simplifying such trees is as follows:
You store a set of trees and their simplified version
For example
* +
/ \ / \
a + and * *
/ \ / \ / \
b c a b a c
(Where a,b,c can be any subtree)
Then, If I find a subtree that matches one of the stored trees, I will
replace it with its simplified version.
If necessary I will repeat the process until the tree is fully simplified.
The problem with this approach is that it can't "combine like terms" in some cases.
For example, if I try to store the tree:
+ *
/ \ and / \
x x 2 x
Then when I try to simplify the expression x+y+x, with the following tree:
+
/ \
x +
/ \
y x
It will not be simplified to 2x+y, because the subtree
+
/ \
x x
Is not contained in the tree, thus the tree will not be simplified.
I tried writing an explicit algorithm that combine like terms but there are too many
cases to consider.
Can anyone please help me find a solution to this problem?
Here is one of the basic ideas which is used in computer algebra systems.
For operators like Plus (+) and Times (*) you can define attributes like Flat (associativity) and Orderless (commutativity). Also don't define Plus and Times as "binary" operators but as "multiple-argument" operators.
So an input like:
Plus(x,Plus(y,x))
in the first step can be transformed (flattened) because of the Flat attribute to
Plus(x,y,x)
in the next step it can be transformed (sorted) because of the Orderless attribute to
Plus(x,x,y)
In your "evaluation" step you can now go through the arguments and "simplify" the expression to:
Plus(Times(2,x),y)
This approach has the advantage that expressions which are "structural equal" are stored in the same "canonical form" and could for example easier compared for "object equality" in the used programming language.
We may consider polynomials
we get the '+'-reducer and '*'-reducer for two polynomes in X
Now in the tree, instead of considering either a scalar or x as node, we may consider an "irreducible" polynomial.
Then we apply the '*'-reducer if the node operator is * or '+'-reducer otherwise which both transform two irreducibles polynome as an new irreducible one.
e.g where P_a, P_b two polynomes and
P_a = {
x0: 1 // term of degree 0 idem 1
x1: 2 // 2x
x3: 4 // 4x^3
}
and P_b = {x1: 3}
we get for sum: P_a + P_b = {x0: 1, x1: 5, x3: 4}
(so tree ['+', P_a, P_b] simplifies as {x: 0, x1: 5, x3: 4})
we get for multiplication: P_a * P_b = {x1: 3, x2: 6, x3: 12}
At the end of the day, we get an irreducible polynome in X.
We can write back that polynome as a binary tree (which is thus a simplified tree):
for each monome (in X^i), write its associated binary tree (which only contains * operator)
e.g: 5x^3 => ['*', ['*', ['*', x, x], x], 5]
then sum them
e.g: 1 + x + x^2 => ['+', 1, ['*', x, 1], ['*', x, x]
Same idea (idem implementing '+'-reducer/'*'-reducer) can be applied with an expression having polynomes in X, Y or Z, or whatever (so in your case, x, y)
below an example of implementation (you may uncomment and pass the tests using nodejs)
// a, b are polynomes of form {monomialKey: scalar, monomialKey2, scalar2, ...}
// a monomial key is e.g x1y2z2
const add = (a, b) => {
const out = Object.assign({}, a)
Object.entries(b).forEach(([monomialKey, scalar]) => {
out[monomialKey] = (out[monomialKey] || 0) + scalar
if (out[monomialKey] === 0) {
delete out[monomialKey]
}
})
return out
}
// transforms x1y2z2 to {x: 1, y: 2, z: 2}
const parseKey = s => s.match(/[a-z]+\d+/g).reduce((o, kv) => {
const [,varname,deg] = kv.match(/([a-z]+)(\d+)/)
o[varname] = parseInt(deg)
return o
}, {})
const writeKey = o => Object.entries(o).reduce((s, [varname, deg]) => s + varname+deg, '')
// simplify monomial, e.g x1y3*x1 => x2y3
const timesMonomialKey = (iA, iB) => {
const a = parseKey(iA)
const b = parseKey(iB)
const out = {}
;[a,b].forEach(x => Object.entries(x).forEach(([varname, deg]) => {
if (deg === 0) return
out[varname] = (out[varname] || 0) + deg
}))
if (Object.keys(out).length === 0) return writeKey({ x: 0 })
return writeKey(out)
}
// a, b both polynomes
const times = (a, b) => {
const out = {}
Object.entries(a).forEach(([monimalKeyA, sA]) => {
Object.entries(b).forEach(([monimalKeyB, sB]) => {
const key = timesMonomialKey(monimalKeyA, monimalKeyB)
out[key] = (out[key] || 0) + sA * sB
if (out[key] === 0) {
delete out[key]
}
})
})
return out
}
const reduceTree = t => { // of the form [operator, left, right] or val
if (!Array.isArray(t)) {
return typeof(t) === 'string'
? { [writeKey({ [t]: 1 })]: 1 } // x => {x1: 1}
: { [writeKey({ x: 0 })]: t } // 5 => {x0: 5}
}
const [op, leftTree, rightTree] = t
const left = reduceTree(leftTree)
const right = reduceTree(rightTree)
return op === '+' ? add(left, right) : times(left, right)
}
const writePolynomial = o => {
const writeMonomial = ([key, s]) => {
const a = parseKey(key)
const factors = Object.entries(a).flatMap(([varname, deg]) => {
return Array.from({length: deg}).fill(varname)
}).concat(s !== 1 ? s : [])
return factors.reduce((t, next) => ['*', t, next])
}
if (Object.keys(o).length === 0) return 0
return Object.entries(o).map(writeMonomial).reduce((t, next) => ['+', t, next])
}
console.log(writePolynomial(reduceTree(['+', ['+', 'x', 'y'], 'x'])))
//const assert = require('assert')
//assert.deepEqual(parseKey('x0y2z3'), { x: 0, y: 2, z: 3 })
//assert.deepEqual(writeKey({ x: 0, y: 2, z: 3 }), 'x0y2z3')
//assert.deepEqual(timesMonomialKey('x1y2', 'x3z1'), 'x4y2z1')
//assert.deepEqual(timesMonomialKey('x0y0', 'z0'), 'x0')
//assert.deepEqual(timesMonomialKey('x0y0', 'z0x1'), 'x1')
//assert.deepEqual(add({x0: 3, x1: 2}, {x0: 4, x3: 5}), {x0: 7, x1: 2, x3: 5})
//assert.deepEqual(add({x0: 3, y1: 2}, {x0: 4, y2: 5}), {x0: 7, y1: 2, y2: 5})
//assert.deepEqual(add({x0: 1}, {x0: -1}), {})
//assert.deepEqual(times({x0: 3, x1: 2}, {x0: 4, x1: 5}), {x0: 12, x1: 23, x2: 10})
//assert.deepEqual(times(
// {x1y0: 3, x1y1: 2},
// {x1y0: 4, x1y1: 5}),
// {x2: 12, x2y1: 23, x2y2: 10}
//)
//assert.deepEqual(reduceTree('x'), {x1: 1})
//assert.deepEqual(reduceTree(['*', 2, 'x']), {x1: 2})
//assert.deepEqual(reduceTree(['+', 2, 'x']), {x0: 2, x1: 1})
//assert.deepEqual(reduceTree(['+', 'x', ['+', 'y', 'x']]), {x1: 2, y1: 1})
//assert.deepEqual(writePolynomial({ x1y1:1, x1y2: 2}), ['+', ['*', 'x', 'y'], ['*', ['*', ['*', 'x', 'y'], 'y'], 2]])
//assert.deepEqual(writePolynomial(reduceTree(['*', ['*', 'x', 'y'], 0])), 0)
//assert.deepEqual(writePolynomial(reduceTree(['+', ['*', ['*', 'x', 'y'], 0], 2])), 2)
//
//// finally your example :)
//assert.deepEqual(writePolynomial(reduceTree(['+', ['+', 'x', 'y'], 'x'])), ['+', ['*', 'x', 2], 'y'])
I am writing a parallel merging algorithm in Rust using scoped-threadpool, but it seems to be producing the correct values in all positions of the output except the first.
I am attempting to adapt the pseudocode from the merge algorithm Wikipedia page:
fn parallel_merge(first: &[i32], second: &[i32], output: &mut [i32]) {
let mut n = first.len();
let mut m = second.len();
let a;
let b;
// Make sure that 'first' is the largest of the two to be merged
if m < n {
a = first;
b = second;
} else {
a = second;
b = first;
let tmp = n;
n = m;
m = tmp;
}
if m <= 0 {
return;
}
let pivot = n / 2;
let s = bisect(a[pivot], b);
let t = pivot + s;
output[t] = a[pivot];
let mut pool = Pool::new(2);
pool.scoped(|scoped| {
let (left, right) = output.split_at_mut(t);
scoped.execute(move || {
parallel_merge(&a[..pivot], &b[..s], left);
});
scoped.execute(move || {
parallel_merge(&a[pivot..], &b[s..], right);
});
});
}
When called with first as the slice [1, 3, 5, 7, 9], second as [2, 4, 6, 8, 10] and a slice of ten zeroes as the initial output, output is left as [0, 2, 3, 4, 5, 6, 7, 8, 9].
What is going wrong? As far as I can see, it matches the pseudocode aside from the unnecessary tracking of indexes.
You've misread the algorithm. m is the length of A:
algorithm merge(A[i...j], B[k...ℓ], C[p...q]) is
let m = j - i,
n = ℓ - k
You have it as the length of B:
let mut m = second.len();
The complete example:
use scoped_threadpool::Pool; // 0.1.9
fn parallel_merge(a: &[i32], b: &[i32], output: &mut [i32]) {
let (a, b) = if a.len() >= b.len() { (a, b) } else { (b, a) };
if a.is_empty() {
return;
}
let pivot = a.len() / 2;
let s = match b.binary_search(&a[pivot]) {
Ok(x) => x,
Err(x) => x,
};
let t = pivot + s;
let (a_left, a_tail) = a.split_at(pivot);
let (a_mid, a_right) = a_tail.split_first().unwrap();
let (b_left, b_right) = b.split_at(s);
let (o_left, o_tail) = output.split_at_mut(t);
let (o_mid, o_right) = o_tail.split_first_mut().unwrap();
*o_mid = *a_mid;
let mut pool = Pool::new(2);
pool.scoped(|scoped| {
scoped.execute(move || parallel_merge(a_left, b_left, o_left));
scoped.execute(move || parallel_merge(a_right, b_right, o_right));
});
}
#[test]
fn exercise() {
let first = [1, 3, 5, 7, 9];
let second = [2, 4, 6, 8, 10];
let mut output = [0; 10];
parallel_merge(&first, &second, &mut output);
assert_eq!(output, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
I have written a basic program of calculations. The program runs fine for some input, while gives TypeError for others. I can't figure out the reason behind this unpredictable behavior. Here's my code -
class Conversion
I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000
result = 0
puts "enter the string"
input = gets.chomp.upcase
temp = input.split(//)
for i in temp do
case i
when 'M'
result = result + M
when 'D'
result = result + D
when 'C'
result = result + C
when 'L'
result = result + L
when 'X'
result = result + X
when 'V'
result = result + V
when 'I'
result = result + I
end
end
puts result
end
The error log is as-
assignment1.rb:22:in +': Array can't be coerced into Fixnum (TypeError)
from assignment1.rb:22:inblock in '
from assignment1.rb:7:in each'
from assignment1.rb:7:in'
from assignment1.rb:1:in `'
Now, when I supply input like mxcd, dcm, lxv etc it works fine. But for inputs like xvi, ivx, icd it gives TypeError.
Need help with it. Thanks in advance.
I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000
is interpreted as
I = ( 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000)
resulting in
I = [1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000]
Substitute the comma's for semicolons.
Why not use a Hash instead of a bunch of constants like so:
class Conversion
CONVERSIONS ={'I' => 1, 'V' => 5, 'X' => 10, 'L' => 50, 'C' => 100, 'D' => 500, 'M' => 1000}.freeze
puts "enter the string"
gets.chomp.upcase.split(//).inject(0) { |sum, i| sum + CONVERSIONS[i].to_i }
end
I have two collections that I want to intersect, and perform a sum operation on matching elements.
For example the collections are (in pseudo code):
col1 = { {"A", 5}, {"B", 3}, {"C", 2} }
col2 = { {"B", 1}, {"C", 8}, {"D", 6} }
and the desired result is:
intersection = { {"B", 4}, {"C", 10} }
I know how to use an IEqualityComparer to match the elements on their name, but how to sum the values while doing the intersection?
EDIT:
The starting collections haven't two items with the same name.
Let's say your input data looks like this:
IEnumerable<Tuple<string, int>> firstSequence = ..., secondSequence = ...;
If the strings are unique in each sequence (i.e there can be no more than a single {"A", XXX} in either sequence) you can join like this:
var query = from tuple1 in firstSequence
join tuple2 in secondSequence on tuple1.Item1 equals tuple2.Item1
select Tuple.Create(tuple1.Item1, tuple1.Item2 + tuple2.Item2);
You might also want to consider using a group by, which would be more appropriate if this uniqueness doesn't hold:
var query = from tuple in firstSequence.Concat(secondSequence)
group tuple.Item2 by tuple.Item1 into g
select Tuple.Create(g.Key, g.Sum());
If neither is what you want, please clarify your requirements more precisely.
EDIT: After your clarification that these are dictionaries - your existing solution is perfectly fine. Here's another alternative with join:
var joined = from kvp1 in dict1
join kvp2 in dict2 on kvp1.Key equals kvp2.Key
select new { kvp1.Key, Value = kvp1.Value + kvp2.Value };
var result = joined.ToDictionary(t => t.Key, t => t.Value);
or in fluent syntax:
var result = dict1.Join(dict2,
kvp => kvp.Key,
kvp => kvp.Key,
(kvp1, kvp2) => new { kvp1.Key, Value = kvp1.Value + kvp2.Value })
.ToDictionary(a => a.Key, a => a.Value);
This will give the result, but there are some caveats. It does an union of the two collections and then it groups them by letter. So if, for example, col1 contained two A elements, it would sum them together and, because now they are 2 A, it would return them.
var col1 = new[] { new { L = "A", N = 5 }, new { L = "B", N = 3 }, new { L = "C", N = 2 } };
var col2 = new[] { new { L = "B", N = 1 }, new { L = "C", N = 8 }, new { L = "D", N = 6 } };
var res = col1.Concat(col2)
.GroupBy(p => p.L)
.Where(p => p.Count() > 1)
.Select(p => new { L = p.Key, N = p.Sum(q => q.N) })
.ToArray();
The best I came up with until now is (my collections are actually Dictionary<string, int> instances):
var intersectingKeys = col1.Keys.Intersect(col2.Keys);
var intersection = intersectingKeys
.ToDictionary(key => key, key => col1[key] + col2[key]);
I'm not sure if it will perform well, at least is it readable.
If your intersection algorithm will result in anonymous type, i.e. ...Select(new { Key = key, Value = value}) then you can easily sum it
result.Sum(e => e.Value);
If you want to sum the "while" doing the intersection, add the value to the accumulator value when adding to the result set.
How would I create a nested grouping for the table below, using LINQ? I want to group by Code, then by Mktcode.
Code Mktcode Id
==== ======= ====
1 10 0001
2 20 0010
1 10 0012
1 20 0010
1 20 0014
2 20 0001
2 30 0002
1 30 0002
1 30 0005
I'd like a dictionary, in the end, like
Dictionary<Code, List<Dictionary<Mktcode, List<Id>>>>
So the values of this dictionary would be
{1, ({10,(0001,0012)}, {20,(0010,0014)}, {30, (0002, 0005)})},
{2, ({20,(0001, 0010)}, {30, (0020)} )}
I'd think of it this way:
You're primarily grouping by code, so do that first
For each group, you've still got a list of results - so apply another grouping there.
Something like:
var groupedByCode = source.GroupBy(x => x.Code);
var groupedByCodeAndThenId = groupedByCode.Select(group =>
new { Key=group.Key, NestedGroup = group.ToLookup
(result => result.MktCode, result => result.Id));
var dictionary = groupedByCodeAndThenId.ToDictionary
(result => result.Key, result => result.NestedGroup);
That will give you a Dictionary<Code, Lookup<MktCode, Id>> - I think that's what you want. It's completely untested though.
You can build lookups (Kinds of Dictionary<,List<>>) using group by into
var lines = new []
{
new {Code = 1, MktCode = 10, Id = 1},
new {Code = 2, MktCode = 20, Id = 10},
new {Code = 1, MktCode = 10, Id = 12},
new {Code = 1, MktCode = 20, Id = 10},
new {Code = 1, MktCode = 20, Id = 14},
new {Code = 2, MktCode = 20, Id = 1},
new {Code = 2, MktCode = 30, Id = 2},
new {Code = 1, MktCode = 30, Id = 2},
new {Code = 1, MktCode = 30, Id = 5},
};
var groups = from line in lines
group line by line.Code
into codeGroup
select new
{
Code = codeGroup.Key,
Items = from l in codeGroup
group l by l.MktCode into mktCodeGroup
select new
{
MktCode = mktCodeGroup.Key,
Ids = from mktLine in mktCodeGroup
select mktLine.Id
}
};
Here's how I'd do it:
Dictionary<Code, Dictionary<MktCode, List<Id>>> myStructure =
myList
.GroupBy(e => e.Code)
.ToDictionary(
g => g.Key,
g => g
.GroupBy(e => e.Mktcode)
.ToDictionary(
g2 => g2.Key,
g2 => g2.Select(e => e.Id).ToList()
)
)
Here's the breakdown of the process:
Group the elements by Code, and create an outer dictionary where the key is that code.
myList
.GroupBy(e => e.Code)
.ToDictionary(
g => g.Key,
For each of the keys in the outer dictionary, regroup the elements by Mktcode and create an inner dictionary.
g => g
.GroupBy(e => e.Mktcode)
.ToDictionary(
g2 => g2.Key,
For each of the keys in the inner dictionary, project the id of those elements and convert that to a list.
g2 => g2.Select(e => e.Id).ToList()
)
)