Generating random math equation using tree - Avoiding Parentheses - math

Edit: This was originally on programmers.stackexchange.com, but since I already had some code I thought it might be better here.
I am trying to generate a random math problem/equation. After researching the best (and only) thing I found was this question: Generating random math expression. Because I needed all 4 operations, and the app that I will be using this in is targeted at kids, I wanted to be able to insure that all numbers would be positive, division would come out even, etc, I decided to use a tree.
I have the tree working, and it can generate an equation as well as evaluate it to a number. The problem is that I am having trouble getting it to only use parentheses when needed. I have tried several solutions, that primaraly involve:
Seeing if this node is on the right of the parent node
Seeing if the node is more/less important then it's parent node (* > +, etc).
Seeing if the node & it's parent are of the same type, and if so if the order matters for that operation.
Not that it matters, I am using Swift, and here is what I have so far:
func generateString(parent_node:TreeNode) -> String {
if(self.is_num){
return self.equation!
}
var equation = self.equation!
var left_equation : String = self.left_node!.generateString(self)
var right_equation : String = self.right_node!.generateString(self)
// Conditions for ()s
var needs_parentheses = false
needs_parentheses = parent_node.importance > self.importance
needs_parentheses = (
needs_parentheses
||
(
parent_node.right_node?.isEqualToNode(self)
&&
parent_node.importance <= self.importance
&&
(
parent_node.type != self.type
&&
( parent_node.order_matters != true || self.order_matters != true )
)
)
)
needs_parentheses = (
needs_parentheses
&&
(
!(
self.importance > parent_node.importance
)
)
)
if (needs_parentheses) {
equation = "(\(equation))"
}
return equation.stringByReplacingOccurrencesOfString("a", withString: left_equation).stringByReplacingOccurrencesOfString("b", withString: right_equation)
}
I have not been able to get this to work, and have been banging my head against the wall about it.
The only thing I could find on the subject of removing parentheses is this: How to get rid of unnecessary parentheses in mathematical expression, and I could not figure out how to apply it to my use case. Also, I found this, and I might try to build a parser (using PEGKit), but I wanted to know if anybody had a good idea to either determine where parentheses need to go, or put them everywhere and remove the useless ones.
EDIT: Just to be clear, I don't need someone to write this for me, I am just looking for what it needs to do.
EDIT 2: Since this app will be targeted at kids, I would like to use the least amount of parentheses possible, while still having the equation come out right. Also, the above algorithm does not put enough parentheses.

I have coded a python 3 pgrm that does NOT use a tree, but does successfully generate valid equations with integer solutions and it uses all four operations plus parenthetical expressions. My target audience is 5th graders practicing order of operations (PEMDAS).
872 = 26 * 20 + (3 + 8) * 16 * 2
251 = 256 - 3 - 6 + 8 / 2
367 = 38 * 2 + (20 + 15) + 16 ** 2
260 = 28 * 10 - 18 - 4 / 2
5000 = 40 * 20 / 4 * 5 ** 2
211 = 192 - 10 / 2 / 1 + 24
1519 = 92 * 16 + 6 + 25 + 16
If the python of any interest to you ... I am working on translating the python into JavaScript and make a web page available for students and teachers.

Related

Logic of computing a^b, and is power a keyword?

I found the following code that is meant to compute a^b (Cracking the Coding Interview, Ch. VI Big O).
What's the logic of return a * power(a, b - 1); ? Is it recursion
of some sort?
Is power a keyword here or just pseudocode?
int power(int a, int b)
{ if (b < 0) {
return a; // error
} else if (b == 0) {
return 1;
} else {
return a * power(a, b - 1);
}
}
Power is just the name of the function.
Ya this is RECURSION as we are representing a given problem in terms of smaller problem of similar type.
let a=2 and b=4 =calculate= power(2,4) -- large problem (original one)
Now we will represent this in terms of smaller one
i.e 2*power(2,4-1) -- smaller problem of same type power(2,3)
i.e a*power(a,b-1)
If's in the start are for controlling the base cases i.e when b goes below 1
This is a recursive function. That is, the function is defined in terms of itself, with a base case that prevents the recursion from running indefinitely.
power is the name of the function.
For example, 4^3 is equal to 4 * 4^2. That is, 4 raised to the third power can be calculated by multiplying 4 and 4 raised to the second power. And 4^2 can be calculated as 4 * 4^1, which can be simplified to 4 * 4, since the base case of the recursion specifies that 4^1 = 4. Combining this together, 4^3 = 4 * 4^2 = 4 * 4 * 4^1 = 4 * 4 * 4 = 64.
power here is just the name of the function that is defined and NOT a keyword.
Now, let consider that you want to find 2^10. You can write the same thing as 2*(2^9), as 2*2*(2^8), as 2*2*2*(2^7) and so on till 2*2*2*2*2*2*2*2*2*(2^1).
This is what a * power(a, b - 1) is doing in a recursive manner.
Here is a dry run of the code for finding 2^4:
The initial call to the function will be power(2,4), the complete stack trace is shown below
power(2,4) ---> returns a*power(2,3), i.e, 2*4=16
|
power(2,3) ---> returns a*power(2,2), i.e, 2*3=8
|
power(2,2) ---> returns a*power(2,1), i.e, 2*2=4
|
power(2,1) ---> returns a*power(2,0), i.e, 2*1=2
|
power(2,0) ---> returns 1 as b == 0

Max to 0 to Max algorithm

First off, let me warn you that my Maths knowledge is fairly limited (hence my coming here to ask about this).
It's a silly example, but what I essentially want is to have a variable number of rows, and be able to set a maximum value, then for each progressive row decrease that value until half way at which point start increasing the value again back up to the maximum by the final row.
To illustrate this... Given that: maxValue = 20, and rows = 5, I need to be able to get to the following values for the row values (yes, even the 0):
row 1: 20
row 2: 10
row 3: 0
row 4: 10
row 5: 20
There are limitations though because I'm trying to do this in Compass which uses SASS. See here for the available operations, but to give you the gist of it, only basic operations are available.
I'm able to loop through the rows, so just need the calculation that will work for each individual row in the series. This is the kind of loop I'm able to use:
$maxValue:20;
$rows:5;
#for $i from 1 through $rows {
// calculation here.
}
I haven't really worked with SASS before, but try something like this using a basic if and the floor function, not sure if will work
// set various variables
$maxValue:20;
$rows:5;
// get row number before middle row, this instance it will be 2
$middleRow = floor( $maxValue / $rows )
// get increment amount, this instance should be 10
$decreaseValue = ( max / floor( rows / 2) )
#for $i from 0 through $rows - 1 {
#if $i <= $middleRow {
( $maxValue- ( $decreaseValue * $i ) )
}
#else{
// times by -1 to make positive value
( $maxValue - ( $decreaseValue * -$i ) ) * -1
}
}
I have tested the above in js ( with relative syntax ) and it yielded the required results ( jsBin example ). Hope this helps

Redefine the infix operators

I am learning Jason Hickey's Introduction to Objective Caml.
Just have a question about Redefine the infix operators.
So in the book, there is such a paragraph:
# let (+) = ( * )
and (-) = (+)
and ( * ) = (/)
and (/) = (-);;
val + : int > int > int = <fun>
val - : int > int > int = <fun>
val * : int > int > int = <fun>
val / : int > int > int = <fun>
# 5 + 4 / 1;;
-: **int = 15**
First, how does these redefinition work?
To me, it seems the functions are running in a kind of indefinite loop, because all the operations seem redefined and connected.
for example, if I do 1+2, then it will be 1 * 2 and since ( * ) = (/), it will be then 1 / 2 and since (/) = (-), then it will be 1-2, so on so forth. Am I right?
Second, will the result of 5 + 4 / 1 be 15, even if the functions are executed only one step further in the redefinition?
So assume the redefinition will be execute one step further, i.e., 1 + 2 will only be 1 * 2 and no more transform, so 5 + 4 / 1 should be 5 * 4 -1, right? then the answer is 19. Am I correct?
To me, it seems the functions are running in a kind of indefinite
loop, because all the operations seem redefined and connected.
Not really, it's just a simultaneous re-definition of infix operators (with the and keyword). What you see is not a recursive definition. In OCaml, recursive definitions are made with let rec (as you may already know).
For the second part of the question, I think it's a matter of operator precedence. Note that in the original expression 5 + 4 / 1 is actually 5 + (4/1) following the usual precedence rules for arithmetic operators. So, I think the conversion simply preserves this binding (sort of). And you get 5 * (4 - 1) = 15.
The key observation (IMHO) is that (+) is being defined by the preexisting definition of ( * ), not by the one that appears a few lines later. Similarly, ( * ) is being defined by the preexisting definition of (/). As Asiri says, this is because of the use of let rather than let rec.
It's also true that in OCaml, precedence and associativity are inherent in the operators and can't be changed by definitions. Precedence and associativity are determined by the first character of the operator.
If you look at the table of operator precedences and associativities in Section 6.7 of the OCaml Manual, you'll see that all the entries are defined for "operators beginning with character X".

VB: how to get the index(es) of an array element if used in For Each

i have the following VB Script written in an .asp file
Dim myArr(5, 6) '// a 6 * 7 array
For i = LBound(myArr, 1) to UBound(myArr, 1)
For j = LBound(myArr, 1) to UBound(myArr, 1)
myArr(i, j) = "i:" & i & ", j:" & j
next
next
Dim i
i = 0
For Each k In myArr
Response.Write("i:" & i ", k:" & k & "<br>")
i = i + 1
Next
using For Each i can iterate through all the array items,
and the question is how can i get the index for each dimension ?
for example: how can i get k index after 10th loop that is 2 and 4 ?
Useful info number 1
First of consider this bit of VBS:
Option Explicit
Dim aaa(1,1,1)
Dim s : s = ""
Dim i, j, k
For i = LBound(aaa, 3) To UBound(aaa, 3)
For j = LBound(aaa, 2) To UBound(aaa, 2)
For k = LBound(aaa, 1) To UBound(aaa, 1)
aaa(k, j, i) = 4 * i + 2 * j + k
Next
Next
Next
Dim x
For Each x in aaa
s = s + CStr(x) + " : "
Next
MsgBox s
This returns "0 : 1 : 2 : 3 : 4 : 5 : 6 : 7 :" which looks good, but note the order of indexers in the inner assignment aaa(k, j, i). If we were to use the more natural aaa(i, j, k) we'd see what appears to us to be a jubbled order returned. Thats because we assume that the left most indexer is the most significant but it isn't its the least significant.
Where bounds start at 0 then for the first dimension all the values in index 0..N are held contigiously where the other dimensions are 0. Then with the next dimension at 1, the next set of 0..N members of the first dimension follow and so on.
Useful info number 2
Given an array of unknown number of dimensions the following code returns the count of dimensions:
Function GetNumberOfDimensions(arr)
On Error Resume Next
Dim i
For i = 1 To 60000
LBound arr, i
If Err.Number <> 0 Then
GetNumberOfDimensions = i - 1
Exit For
End If
Next
End Function
Solution
Given an array construct like this.
Dim arr(3,3,3)
Dim s : s = ""
Dim i, j, k
For i = LBound(arr, 3) To UBound(arr, 3)
For j = LBound(arr, 2) To UBound(arr, 2)
For k = LBound(arr, 1) To UBound(arr, 1)
arr(k, j, i) = 16 * i + 4 * j + k
Next
Next
Next
Here is some code that is able to determine the set of indices for each item in an array of arbitary dimensions and sizes.
Dim dimCount : dimCount = GetNumberOfDimensions(arr)
Redim dimSizes(dimCount - 1)
For i = 1 To dimCount
dimSizes(i - 1) = UBound(arr, i) - LBound(arr, i) + 1
Next
Dim index : index = 0
Dim item
For Each item in arr
s = "("
Dim indexValue, dimIndex
indexValue = index
For dimIndex = 0 To dimCount - 1
s = s + CStr((indexValue mod dimSizes(dimIndex)) - LBound(arr, dimIndex + 1)) + ", "
indexValue = indexValue \ dimSizes(dimIndex)
Next
Response.Write Left(s, Len(s) - 2) + ") = " + Cstr(item) + "<br />"
index = index + 1
Next
An interesting acedemic exercise, not sure how useful it is.
You can't. For each is defined to iterate over objects without having to know the amount of objects (as defined in the IEnumerable interface) at the moment the next object is returned (making multithreading possible).
It is also not specified that you'll receive your objects in exact the same order as you put them (although, I never experienced an other order for arrays), that depends on the Enumerator Interface object that is specified for the collection.
Fortunately, there are other tricks to do what you want, but the implementation depends on the problem you are trying to solve.
For example, you can use an array with arrays, the ArrayList class from System.Collections.ArrayList or create an own class where you store your values or objects.
Please note: There are some discussions about this correctness of this answer, see the comments below. I'll study the subject and will share any relevant experiences I got from them.
You could create a helper object like this:
Option Explicit
dim myArr(5,6)
dim i, j, k
For i = LBound(myArr, 1) to UBound(myArr, 1)
For j = LBound(myArr, 2) to UBound(myArr, 2)
Set myArr(i, j) = [new LookupObject]("i:" & i & ", j:" & j, i, j)
next
next
For Each k In myArr
Response.Write("This is k:" & k & "<br>")
Response.Write("i index of k: " & k.I & "<br>")
Response.Write("j index of k: " & k.J & "<br>")
Next
Public Function [new LookupObject](value, i, j)
Set [new LookupObject] = (new cls_LookupObject).Init(value, i, j)
End Function
Class cls_LookupObject
Private value_, i_, j_
Public Function Init(value, i, j)
i_ = i
j_ = j
value_ = value
Set Init = me
End Function
Public Default Property Get Value()
Value = value_
End Property
Public Property Get I()
I = i_
End Property
Public Property Get J()
J = j_
End Property
End Class
DISCLAIMER: As I created this code on a non Windows machine, I couldn't test it. You could find some syntax or design errors. The naming is not very great, but this way it sticks more to your concept.
Although, it seems you are searching for a simple solution. Not one that will introduce more 'challenges': When you want to pass around values in the array that keep their internal indices, you need to Set them instead of just assigning them: this decreases portability.
And when you use objects, you need to know how Object References work in contrast to primitives, otherwise you'll get some unexpected behavior of values changing when you don't expected it.
UPDATED
If a person interested in how VBScript compares to other languages with regard
to arrays, foreach looping, and especially obtaining information about the
position of the element delivered by "For Each" in the collection looped over,
would pose a question like:
How does VBScript compare to other languages with regard to arrays,
foreach looping, and especially obtaining information about the
position of the element delivered by "For Each" in the collection
looped over?
then a short answer would have been available long ago:
A foreach loop construct can deliver
a pointer (memory address) - as e.g. C/C++ does; then you have to
de-reference the pointer to get at the element which you can even
change; positional info is optainable by pointer arithmetic)
a reference (alias) (as e.g. Perl does; that allows modification,
but obviously no computing of positions (unless the element
accidentially contains such info))
a copy (as e.g. Python or VBScript do; neither modification nor
retrieval of meta info is possible (unless some kind and clever
souls like AutomatedChaos or AnthonyWJones work their heart out to
implement a C/C++ alike solution by submitting a loop variable to
DIVs and MODs resp. to design a class that allows to augment the
plain/essential data values with meta info)
You may safely ignore the rest of my answer; I just don't want to delete the
following text which provides some context for the discussion.
The problem can't be dealt with, until
(1) armen describes the context of the real world problem in real world terms - where do the arrays come from, how many dimensions are possible, what determines the dimensional
structure (row/column/...), which operations must be done in the For Each loop, why/how are the indices important for these operations
(2) all contributors get their selectors for the dimensions right:
For i = LBound(myArr, 1) to UBound(myArr, 1)
For j = LBound(myArr, 1) to UBound(myArr, 1)
or variations thereof are obviously wrong/misleading. Without replacing the 1 in one line by 2, it's not clear, what row/column-structure the code is meant for.
To prove that I'm willing to contribute in a more constructive way, I throw in a function to get the (number of) dimensions for an arbitrary array:
Function getDimensions(aVBS)
Dim d : d = 0
If IsArray(aVBS) Then
For d = 1 To 60
On Error Resume Next
UBound aVBS, d + 1
If Err.Number Then Exit For
On Error GoTo 0
Next
End If
getDimensions = d
End Function ' getDimensions
(based on code by M. Harris and info from the VBScript Docs)
Update: Still not a solution, but some food for thought
As armen (upto now) didn't provide the real story of his problem, I try to
give you a fictonal one (to put a context to the rows and columns and whatever
you may call the thingies in the third dimension):
Let's say there is a school - Hogmond - teaching magical programming. VBScript
is easy (but in the doghouse), so there are just three tests and students are
admitted mid term (every penny counts). JScript is harder, so you have to do the
full course and additional tests may be sheduled during the term, if pupils
prove thick. F# is more complicated, so each test has to be judged in terms of
multiple criteria, some of which may be be agreed upon during the term (the
teachers are still learning). C# is such a 'good' language, that there is just
one test.
So at the end of the term the principal - Mr. Bill 'Sauron' Stumblegates - has
an .xls, containing a sheet:
(Doreen was accepted during the last week of the term) and a sheet:
(for your peace of mind, 120 additional tests are hidden); the F# results
are kept in a .txt file:
# Results of the F# tests
# 2 (fixed) students, 3 (fixed) test,
# 4>5 (dynamic) criteria for each test
Students Ann Bill
Test TA TB TC TA TB TC
Criteria
CA 1 2 3 4 5 6
CB 7 8 9 10 11 12
CC 13 14 15 16 17 18
CD 19 20 21 22 23 24
# CE 25 26 27 28 29 30
(because I know nothing about handling three+-dimensional data in Excel).
Now we have a context to think about
data: it's important that Mary scored 9 for the eval test, but
whether that info is stored in row 5 or 96 is not an inherent
property of the data [Implies that you should think twice before you
embark on the (taken by itself: impressive) idea of AutomatedChaos
to create objects that combine (essential) data and (accidential)
info about positions in a (n arbitrary) structure.]
processing: some computations - especially those that involve the
whole dataset - can be done with no regard to rows or colums (e.g.
average of all scores); some may even require a
restructuring/reordering (e.g. median of all scores); many
computations - all that involve selection/grouping/subsets of the
data - just can't be done without intimate knowledge about the
positions of the data items. armen, however, may not be interested
in processing at all - perhaps all he needs the indices for is to
identify the elements while displaying them. [So it's futile to
speculate about questions like "Shouldn't Excel/the database do the
processing?", "Will the reader be content with 'D5: 9' or does he
whish to see 'Mary/eval: 9' - and would such info be a better
candidate for AutomatedChaos' class?", "What good is a general 'For
Each' based function/sub that handles arrays of every dimension, if
assignments - a(i)=, b(i,j)=, c(i,j,k)= ... - can't be
parameterized?"]
structure/layout: the choice of how you put your data into rows and
columns is determined by convenience (vertical scrolling perfered),
practical considerations (append new data 'at the end'), and
technical reasons (VBScript's 'ReDim Preserve' can grow (dynamic)
arrays in the last dimension only) - so for each layout that makes
sense for a given context/task there are many other structures that
are better in other circumstances (or even the first context).
Certainly there is no 'natural order of indexers'.
Now most programmers love writing/written code more than reading stories (and
some more than to think about/plan/design code), so here is just one example
to show what different beasts (arrays, 'iterators') our pipe dream/magical
one-fits-all-dimensions 'For Each' strategy has to cope with:
Given two functions that let you cut data from Excel sheets:
Function getXlsRange(sSheet, sRange)
Dim oX : Set oX = CreateObject("Excel.Application")
Dim oW : Set oW = oX.Workbooks.Open(resolvePath("..\data\hogmond.xls"))
getXlsRange = oW.Sheets(sSheet).Range(sRange).Value
oW.Close
oX.Quit
End Function ' getXlsRange
Function getAdoRows(sSQL)
Dim oX : Set oX = CreateObject("ADODB.Connection")
oX.open Join(Array( _
"Provider=Microsoft.Jet.OLEDB.4.0" _
, "Data Source=" & resolvePath("..\data\hogmond.xls") _
, "Extended Properties=""" _
& Join(Array( _
"Excel 8.0" _
, "HDR=No" _
, "IMEX=1" _
), ";" ) _
& """" _
), ";")
getAdoRows = oX.Execute(sSQL).GetRows()
oX.Close
End Function ' getAdoRows
(roll your own resolvePath() function or hard code the file spec)
and a display Sub (that uses armen's very good idea to introduce a
loop counter variable):
Sub showAFE(sTitle, aX)
Dim i, e
WScript.Echo "For Each:", sTitle
WScript.Echo "type:", VarType(aX), TypeName(aX)
WScript.Echo "dims:", getDimensions(aX)
WScript.Echo "lb :", LBound(aX, 1), LBound(aX, 2)
WScript.Echo "ub :", UBound(aX, 1), UBound(aX, 2)
WScript.Echo "s :", UBound(aX, 1) - LBound(aX, 1) + 1 _
, UBound(aX, 2) - LBound(aX, 2) + 1
i = 0
For Each e In aX
WScript.Echo i & ":", e
i = i + 1
Next
End Sub ' showAFE
you can use code like
showAFE "VTA according to XlsRange:", getXlsRange("VTA", "B3:D4")
showAFE "VTA according to AdoRows:", getAdoRows("SELECT * FROM [VTA$B3:D4]")
to get your surprise of the weekend:
For Each: VTA according to XlsRange:
type: 8204 Variant()
dims: 2
lb : 1 1
ub : 2 3
s : 2 3
0: 1
1: 2
2: 3
3: 4
4: 5
5: 6
For Each: VTA according to AdoRows:
type: 8204 Variant()
dims: 2
lb : 0 0
ub : 2 1
s : 3 2
0: 1
1: 3
2: 5
3: 2
4: 4
5: 6
and despair:
Mr. Stumblegates type system hides the fact that these two arrays
have a very different nature (and the difference between fixed and
dynamic arrays is ignored too)
You can create all kinds of arrays in VBScript as long as they are
zero-based (no chance of creating and/or restructuring Range-born
arrays and keep their (accidential!) one-based-ness)
Getting one set of data with (necessarily) one layout via two
different methods will deliver the data with two different
structures
If you ask "For Each" to enumerate the data, the sequence you get is
determined by the iterator and not predictable (you have to
check/experiment). (Accentuating the freedom/role of the iterator is
the one nugget in AutomatedChaos' first answer)
[Don't read this, if you aren't interested in/can't stand a pedantic diatribe:
which still has a better score than AnthonyWJones' contribution, because at
least one person who admittedly has anderstood neither question nor answer
upvotes it, because of the reference to .ArrayList - which isn't relevant at all
to armen's question, because there is no way to make an ArrayList
multi-dimensional (i.e.: accessible by the equivalent of al(1,2,3)). Yes
"IEnumerable" (a pure .NET concept) and "multithread" are impressive keywords
and there are 'live' collections (e.g. oFolder.Files) that reflect 'on the fly'
modifications, but no amount of (single!)-threading will let you modify a humble
VBScript array while you loop - Mr. Stumblegates is a harsh master:
Dim a : a = Array(1, 2, 3)
Dim e
WScript.Stdout.WriteLine "no problem looping over (" & Join(a, ", ") & ")"
For Each e In a
WScript.Stdout.Write " " & e
Next
ReDim Preserve a(UBound(a) + 1)
a(UBound(a)) = 4
WScript.Stdout.WriteLine
WScript.Stdout.WriteLine "no problem growing the (dynamic) array (" & Join(a, ", ") & ")"
WScript.Stdout.WriteLine "trying to grow in loop"
For Each e In a
WScript.Stdout.Write " " & e
If e = 3 Then
On Error Resume Next
ReDim Preserve a(UBound(a) + 1)
If Err.Number Then WScript.Stdout.Write " " & Err.Description
On Error GoTo 0
a(UBound(a)) = 5
End If
Next
WScript.Stdout.WriteLine
output:
no problem looping over (1, 2, 3)
1 2 3
no problem growing the (dynamic) array (1, 2, 3, 4)
trying to grow in loop
1 2 3 This array is fixed or temporarily locked 5
Another elaboration of a blanket statement: Even good programmers make mistakes,
especially if they are eager to help, have to work under unfavorable conditions
(Mr. Stumblegates did his utmost to make sure that you can't use/publish VBScript
code without extensive testing), have a job and a live, or just a bad moment.
This, however, does not change the fact that some code fragments/statements are
useless or even dangerous to SO readers who - because of votes - think they have
found a solution to their problem. Quality of code/text is an essential property
of the content alone, who wrote it is just accidential. But how to be 'objective'
in a context where "Jon Doe's code" is the natural way to refer to lines like
for i = 0 to ubound(myArr)
for y = 0 to ubound(myArr, 1)
[UBound(a) and UBound(a, 1) are synonyms, so this will create havoc as soon
as the UBounds of the different dimensions are not (accidentially) the same]
and votes for content are summed up under the reputations of persons? (Would SO
list millions of answers without the reputation system? Would I put less time/work
in my contributions without the points? I hope/guess not, but I'm a human too.)
So I encourage you to downvote this elaborate (at least) until I correct the
limit of 60 in my getDimensions() function. You can't hurt my feelings; I think
I'm blameless, because all I did was to rely on the docs:
Dimensions of an array variable; up to 60 multiple dimensions may be
declared.
(What I'm a bit ashamed of is that I had feelings of superiority, when I looked
at the 999 or the 60000 in other people's code - as I said: I'm only human too;
and: Don't put your trust in Mr. Stumblegates, but check:
Dim nDim
For Each nDim In Array(3, 59, 60, 62, 64, 65, 70)
ReDim aDim(nDim)
Dim sDim : sDim = "ReDim a" & nDim & "(" & Mid(Join(aDim, ",0"), 2) & ")"
WScript.Echo sDim
On Error Resume Next
Execute sDim
If Err.Number Then WScript.Echo Err.Description
On Error GoTo 0
Next
output:
ReDim a3(0,0,0)
...
ReDim a64(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,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,0,0,0,0)
ReDim a65(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,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,0,0,0,0,0)
Subscript out of range
...
)
Not to conclude in destructive mode: I still hope that my harping on the topic
"bounds used in nested loops to specify indexers (especially such of different
ranges)" will magically cause a lot of code lines here to be changed in the near
future - or aren't we all students at Hogmond?
]
Use nested For loops, instead of For Each
for i = 0 to ubound(myArr)
for y = 0 to ubound(myArr, 2)
' do something here...
next
next

MATLAB: What happens for a global variable when running in the parallel mode?

What happens for a global variable when running in the parallel mode?
I have a global variable, "to_be_optimized_parameterIndexSet", which is a vector of indexes that should be optimized using gamultiobj and I have set its value only in the main script(nowhere else).
My code works properly in serial mode but when I switch to parallel mode (using "matlabpool open" and setting proper values for 'gaoptimset' ) the mentioned global variable becomes empty (=[]) in the fitness function and causes this error:
??? Error using ==> parallel_function at 598
Error in ==> PF_gaMultiFitness at 15 [THIS LINE: constants(to_be_optimized_parameterIndexSet) = individual;]
In an assignment A(I) = B, the number of elements in B and
I must be the same.
Error in ==> fcnvectorizer at 17
parfor (i = 1:popSize)
Error in ==> gamultiobjMakeState at 52
Score =
fcnvectorizer(state.Population(initScoreProvided+1:end,:),FitnessFcn,numObj,options.SerialUserFcn);
Error in ==> gamultiobjsolve at 11
state = gamultiobjMakeState(GenomeLength,FitnessFcn,output.problemtype,options);
E rror in ==> gamultiobj at 238
[x,fval,exitFlag,output,population,scores] = gamultiobjsolve(FitnessFcn,nvars, ...
Error in ==> PF_GA_mainScript at 136
[x, fval, exitflag, output] = gamultiobj(#(individual)PF_gaMultiFitness(individual, initialConstants), ...
Caused by:
Failure in user-supplied fitness function evaluation. GA cannot continue.
I have checked all the code to make sure I've not changed this global variable everywhere else.
I have a quad-core processor.
Where is the bug? any suggestion?
EDIT 1: The MATLAB code in the main script:
clc
clear
close all
format short g
global simulation_duration % PF_gaMultiFitness will use this variable
global to_be_optimized_parameterIndexSet % PF_gaMultiFitness will use this variable
global IC stimulusMoment % PF_gaMultiFitness will use these variables
[initialConstants IC] = oldCICR_Constants; %initialize state
to_be_optimized_parameterIndexSet = [21 22 23 24 25 26 27 28 17 20];
LB = [ 0.97667 0.38185 0.63529 0.046564 0.23207 0.87484 0.46014 0.0030636 0.46494 0.82407 ];
UB = [1.8486 0.68292 0.87129 0.87814 0.66982 1.3819 0.64562 0.15456 1.3717 1.8168];
PopulationSize = input('Population size? ') ;
GaTimeLimit = input('GA time limit? (second) ');
matlabpool open
nGenerations = inf;
options = gaoptimset('PopulationSize', PopulationSize, 'TimeLimit',GaTimeLimit, 'Generations', nGenerations, ...
'Vectorized','off', 'UseParallel','always');
[x, fval, exitflag, output] = gamultiobj(#(individual)PF_gaMultiFitness(individual, initialConstants), ...
length(to_be_optimized_parameterIndexSet),[],[],[],[],LB,UB,options);
matlabpool close
some other piece of code to show the results...
The MATLAB code of the fitness function, "PF_gaMultiFitness":
function objectives =PF_gaMultiFitness(individual, constants)
global simulation_duration IC stimulusMoment to_be_optimized_parameterIndexSet
%THIS FUNCTION RETURNS MULTI OBJECTIVES AND PUTS EACH OBJECTIVE IN A COLUMN
constants(to_be_optimized_parameterIndexSet) = individual;
[smcState , ~, Time]= oldCICR_CompCore(constants, IC, simulation_duration,2);
targetValue = 1; % [uM]desired [Ca]i peak concentration
afterStimulus = smcState(Time>stimulusMoment,14); % values of [Ca]i after stimulus
peak_Ca_value = max(afterStimulus); % smcState(:,14) is [Ca]i
if peak_Ca_value < 0.8 * targetValue
objectives(1,1) = inf;
else
objectives(1, 1) = abs(peak_Ca_value - targetValue);
end
pkIDX = peakFinder(afterStimulus);
nPeaks = sum(pkIDX);
if nPeaks > 1
peakIndexes = find(pkIDX);
period = Time(peakIndexes(2)) - Time(peakIndexes(1));
objectives(1,2) = 1e5* 1/period;
elseif nPeaks == 1 && peak_Ca_value > 0.8 * targetValue
objectives(1,2) = 0;
else
objectives(1,2) = inf;
end
end
Global variables do not get passed from the MATLAB client to the workers executing the body of the PARFOR loop. The only data that does get sent into the loop body are variables that occur in the text of the program. This blog entry might help.
it really depends on the type of variable you're putting in. i need to see more of your code to point out the flaw, but in general it is good practice to avoid assuming complicated variables will be passed to each worker. In other words anything more then a primitive may need to be reinitialized inside a parallel routine or may need have specific function calls (like using feval for function handles).
My advice: RTM

Resources