I have been using (or attempting to, most of the modules I have I have borrowed from other Wikis as my understanding of Lua is limited at best) Lua-based modules and their invoking templates (i.e., the ones that invoke them with {{#invoke:}}) on my Wiki for some time and I have an infobox for chemical compounds (my Chembox) which includes inputs for the numbers of atoms of each chemical element present in the compound (i.e., those numbers used in the compound's molecular formula) and the molar mass of the compound. I was thinking, since it is possible to calculate the molar mass of the compound based on its molecular formula it might be possible to create a Lua module that can do this automatically for me, eliminating the need for me to input the molar mass myself into these infoboxes.
So my question is basically, how do I do this?
Research
My background is in mathematics, so I felt the most straight-forward way of doing this is to set up two vectors, A and B, and perform a dot-product between them. A would contain the user-defined variables, namely, those provided to the template that invokes the module. For example, say we were talking about ethanol (C2H6O) then the template may look like:
{{Molar mass calculator
|C = 2
|H = 6
|O = 1
}}
. B would contain the average atomic mass of each element in grams per mol (g/mol). This vector will be self-provided (i.e., by me, I have a list of 84 elements found in sufficient quantities in nature for these standard atomic weights to be available, with their standard atomic weights also listed. So I will provide them in the Lua code if you just show me where to add them to the code.).
I have looked up dot products in Lua to see if this is possible and how to do them and found this code (http://rosettacode.org/wiki/Dot_product#Lua):
function dotprod(a, b)
local ret = 0
for i = 1, #a do
ret = ret + a[i] * b[i]
end
return ret
end
print(dotprod({1, 3, -5}, {4, -2, 1}))
I believe this is what you are looking for :)
Populate the "AtomicWeightLookup" table with your own values.
There is an example call to the "Calculate" function at the end of the program.
local AtomicWeightLookup = {
C = 12.01,
H = 1.001,
O = 16
}
local function Calculate(Input)
-- Input Example: {C = 2, H = 6, O = 1}
local Result = 0
-- Iterate through Input table
for Element,Quantity in next,Input do
-- If element is not found in table, assume 0 weight.
local AtomicWeight = AtomicWeightLookup[Element] or 0
-- Multiply
Result = Result + Quantity * AtomicWeight
end
return Result
end
-- EXAMPLE
print(Calculate({C = 2, H = 6, O = 1}))
Via emailing the Wikitech-I mailing list (wikitech-I#lists.sourceforge.net) I received an answer. Module:Molar mass calculator is to have the code (the round function is designed to round the end result to the nearest three decimal places, as I later decided that I wanted this capability too):
local p = {};
function p.calc(frame)
local atomicWeights = mw.loadData( 'Module:Standard atomic weight' )
local total = 0
for element, quantity in pairs( frame:getParent().args ) do
if quantity ~= "" then
local atomicWeight = atomicWeights[element] or error( 'Element "' .. element .. '" is not known. Please add it to [[Module:Standard atomic weight]] if it\'s not a typo.' )
quantity = tonumber( quantity ) or error( 'Quantity for ' .. element .. ' is not a number.' )
total = total + atomicWeight * quantity
end
end
function round(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
return round(total,3)
end
return p
Module:Standard atomic weight has the code:
local M = {}
M['Ag'] = 107.8682 -- Silver (Ag)
M['As'] = 74.921595 -- Arsenic (As)
M['Au'] = 196.966569 -- Gold (Au)
M['B'] = 10.8135 -- Boron (B)
M['Ba'] = 137.327 -- Barium (Ba)
M['Bi'] = 208.9804 -- Bismuth (Bi)
M['Br'] = 79.904 -- Bromine (Br)
M['C'] = 12.0106 -- Carbon (C)
M['Ca'] = 40.078 -- Calcium (Ca)
M['Cl'] = 35.4515 -- Chlorine (Cl)
M['Co'] = 58.933194 -- Cobalt (Co)
M['Cu'] = 63.546 -- Copper (Cu)
M['F'] = 18.998403163 -- Fluorine (F)
M['Fe'] = 55.845 -- Iron (Fe)
M['Ga'] = 69.723 -- Gallium (Ga)
M['H'] = 1.007975 -- Hydrogen (H)
M['Hg'] = 200.592 -- Mercury (Hg)
M['I'] = 126.90447 -- Iodine (I)
M['K'] = 39.0983 -- Potassium (K)
M['Li'] = 6.9675 -- Lithium (Li)
M['Mg'] = 24.3055 -- Magnesium (Mg)
M['Mn'] = 54.938044 -- Manganese (Mn)
M['N'] = 14.006855 -- Nitrogen (N)
M['Na'] = 22.98976928 -- Sodium (Na)
M['Ni'] = 58.6934 -- Nickel (Ni)
M['O'] = 15.9994 -- Oxygen (O)
M['P'] = 30.973761998 -- Phosphorus (P)
M['Pb'] = 207.2 -- Lead (Pb)
M['Pt'] = 195.084 -- Platinum (Pt)
M['S'] = 32.0675 -- Sulfur (S)
M['Se'] = 78.971 -- Selenium (Se)
M['Sr'] = 87.62 -- Strontium (Sr)
M['Tl'] = 204.3835 -- Thallium (Tl)
M['Zn'] = 65.38 -- Zinc (Zn)
return M
and Template:Molar mass calculator:
{{#invoke:Molar mass calculator|calc}} g/mol
Related
I'm trying to do a solver for equations. When I run the code the X variable appears to be undefined, but it prints out perfectly. What am I missing?
I should give the program some numbers, than operations as Macros and it should create an outer product matrix of the operations applied.
function msu()
print("Insert how many values: ")
quantity = parse(Int64, readline())
values = []
for i in 1:quantity
println("x$i")
num1 = parse(Float64, readline())
push!(values, num1)
end
println(values)
print("How many operations? ")
quantity = parse(Int64, readline())
ops = []
for i in 1:quantity
push!(ops, Meta.parse(readline()))
end
mat = zeros((quantity, quantity))
for i in 1:length(mat)
sum = 0
for j in 1:length(values)
# here begins problems, the following prints are for debugging purpose
print(length(values))
func = Meta.parse("$(ops[convert(Int64, ceil(j / quantity))]) * $(ops[convert(Int64, j % quantity)])")
print(func)
x = values[j]
println(x)
sum += eval(func)
end
mat[i] = sum
end
println(mat)
end
msu()
The original code was in Spanish, if you find any typo it's probably because I skipped a translation.
I want to have objects interact with specific interactions depending on their type.
Example problem: I have four particles, two are type A, and 2 are type B. when type A's interact I want to use the function
function interaction(parm1, parm2)
return parm1 + parm2
end
when type B's interact I want to use the function
function interaction(parm1, parm2)
return parm1 * parm2
end
when type A interacts with type B I want to use function
function interaction(parm1, parm2)
return parm1 - parm2
end
These functions are purposefully over simple.
I want to calculate a simple summation that depends on pairwise interactions:
struct part
parm::Float64
end
# part I need help with:
# initialize a list of length 4, where the entries are `struct part`, and the abstract types
# are `typeA` for the first two and `typeB` for the second two. The values for the parm can be
# -1.0,3, 4, 1.5 respectively
energy = 0.0
for i in range(length(particles)-1)
for j = i+1:length(particles)
energy += interaction(particles[i].parm, particles[j].parm)
end
end
println(energy)
assuming the use of parameters being particle[1].parm = -1, particle[2].parm = 3, particle[3].parm = 4, particle[4].parm = 1.5, energy should account for the interactions of
(1,2) = -1 + 3 = 2
(1,3) = -1 - 4 = -5
(1,4) = -1 - 1.5 = -2.5
(2,3) = 3 - 4 = -1
(2,4) = 3 - 1.5 = 1.5
(3,4) = 4 * 1.5 = 6
energy = 1
Doing this with if statements is almost trivial but not extensible. I am after a clean, tidy Julia approach...
You can do this (I use the simplest form of the implementation as in this case it is enough and it is explicit what happens I hope):
struct A
parm::Float64
end
struct B
parm::Float64
end
interaction(p1::A, p2::A) = p1.parm + p2.parm
interaction(p1::B, p2::B) = p1.parm * p2.parm
interaction(p1::A, p2::B) = p1.parm - p2.parm
interaction(p1::B, p2::A) = p1.parm - p2.parm # I added this rule, but you can leave it out and get MethodError if such case happens
function total_energy(particles)
energy = 0.0
for i in 1:length(particles)-1
for j = i+1:length(particles)
energy += interaction(particles[i], particles[j])
end
end
return energy
end
particles = Union{A, B}[A(-1), A(3), B(4), B(1.5)] # Union makes sure things are compiled to be fast
total_energy(particles)
I have no idea how to do this in your language, but what you need is an analogue to what we call the strategy pattern in object-oriented programming. A strategy is a pluggable, reusable algorithm. In Java I’d make an interface like:
interface Interaction<A, B>
{
double interact(A a, B b)
}
Then implement this three times and reuse those parts wherever you need things to interact. Another method can take an Interaction and use it without knowing how it’s implemented. I think this is the effect you’re after. Sorry I don’t know how to translate into your dialect.
I am wondering if its possible to search in the database with the given scrambled words.
I have a mobs table in database and it holds the name of the monster names
If given monster name is A Golden Dregon or A Golden Dfigon or A Gelden Dragon I want it to find A Golden Dragon or with the matches that close to it from database. Usually one or two letters at max is given like this as scrambled.
Is that possible with just SQL queries? Or should I build the query by parsing the given monster name?
I am using LUA for the code side.
I have come to know this search type as a fuzzy search. I mainly program in JS and use fuse.js all the time for this kind of problem.
Fuzzy Searches are based on the Levenshtein algorithm that rate the distance of two strings. When you have this distance value you can sort or drop elements from a list based on the score.
I found the algorithm in lua here.
function levenshtein(s, t)
local s, t = tostring(s), tostring(t)
if type(s) == 'string' and type(t) == 'string' then
local m, n, d = #s, #t, {}
for i = 0, m do d[i] = { [0] = i } end
for j = 1, n do d[0][j] = j end
for i = 1, m do
for j = 1, n do
local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1
d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost)
end
end
return d[m][n]
end
end
As explained in the site you compare two strings like so and get a score based on the distance of them, then sort or drop the items being search based on the scores given. As this is CPU expensive I would suggest caching or use a memoize function to store common mistakes.
levenshtein('referrer', 'referrer') -- zero distance
>>> 0
levenshtein('referrer', 'referer') -- distance of one character
>>> 1
levenshtein('random', 'strings') -- random big distance
>>> 6
Got a simple version of it working in lua here I must say lua is an easy language to pick up and start coding with.
local monsters = {'A Golden Dragon', 'Goblins', 'Bunny', 'Dragoon'}
function levenshtein(s, t)
local s, t = tostring(s), tostring(t)
if type(s) == 'string' and type(t) == 'string' then
local m, n, d = #s, #t, {}
for i = 0, m do d[i] = { [0] = i } end
for j = 1, n do d[0][j] = j end
for i = 1, m do
for j = 1, n do
local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1
d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost)
end
end
return d[m][n]
end
end
--Fuzzy Search Returns the Best Match in a list
function fuzzySearch(list, searchText)
local bestMatch = nil;
local lowestScore = nil;
for i = 1, #list do
local score = levenshtein(list[i], searchText)
if lowestScore == nil or score < lowestScore then
bestMatch = list[i]
lowestScore = score
end
end
return bestMatch
end
print ( fuzzySearch(monsters, 'golen dragggon') )
print ( fuzzySearch(monsters, 'A Golden Dfigon') )
print ( fuzzySearch(monsters, 'A Gelden Dragon') )
print ( fuzzySearch(monsters, 'Dragooon') ) --should be Dragoon
print ( fuzzySearch(monsters, 'Funny') ) --should be Bunny
print ( fuzzySearch(monsters, 'Gob') ) --should be Goblins
Output
A Golden Dragon
A Golden Dragon
A Golden Dragon
Dragoon
Bunny
Goblins
For SQL
You can try to do this same algorithm in T-SQL as talked about here.
In SQLlite there is an extension called editdist3 which also uses this algorithm the docs are here.
I would be hard to compensate for all the different one and two letter scrambled combinations, but you could create a lua table of common misspellings of "A Golden Dragon" check if it is in the table. I have never used lua before but here is my best try at some sample code:
local mob_name = "A Golden Dregon"--you could do something like, input("Enter mob name:")
local scrambled_dragon_names = {"A Golden Dregon", "A Golden Dfigon", "A Gelden Dragon"}
for _,v in pairs(scrambled_dragon_names) do
if v == mob_name then
mob_name = "A Golden Dragon"
break
end
end
I really hope I have helped!
P.S. If you have anymore questions go ahead and comment and I will try to answer ASAP.
You will have to parse the given monster name to some extent, by making assumptions about how badly it is misspelled. For example, if the user supplied the name
b fulden gorgon
There is no way in hell you can get to "A Golden Dragon". However, if you assume that the user will always get the first and last letters of every word correctly, then you could parse the words in the given name to get the first and last letters of each word, which would give you
"A", "G" "n", "D" "n"
Then you could use the LIKE operator in your query, like so:
SELECT * FROM mobs WHERE monster_name LIKE 'A G%n D%n';
The main point here is what assumptions you make about the misspelling. The closer you can narrow it down, the better your query results will be.
I've written a rudimentary algorithm in Fortran 95 to calculate the gradient of a function (an example of which is prescribed in the code) using central differences augmented with a procedure known as Richardson extrapolation.
function f(n,x)
! The scalar multivariable function to be differentiated
integer :: n
real(kind = kind(1d0)) :: x(n), f
f = x(1)**5.d0 + cos(x(2)) + log(x(3)) - sqrt(x(4))
end function f
!=====!
!=====!
!=====!
program gradient
!==============================================================================!
! Calculates the gradient of the scalar function f at x=0using a finite !
! difference approximation, with a low order Richardson extrapolation. !
!==============================================================================!
parameter (n = 4, M = 25)
real(kind = kind(1d0)) :: x(n), xhup(n), xhdown(n), d(M), r(M), dfdxi, h0, h, gradf(n)
h0 = 1.d0
x = 3.d0
! Loop through each component of the vector x and calculate the appropriate
! derivative
do i = 1,n
! Reset step size
h = h0
! Carry out M successive central difference approximations of the derivative
do j = 1,M
xhup = x
xhdown = x
xhup(i) = xhup(i) + h
xhdown(i) = xhdown(i) - h
d(j) = ( f(n,xhup) - f(n,xhdown) ) / (2.d0*h)
h = h / 2.d0
end do
r = 0.d0
do k = 3,M r(k) = ( 64.d0*d(k) - 20.d0*d(k-1) + d(k-2) ) / 45.d0
if ( abs(r(k) - r(k-1)) < 0.0001d0 ) then
dfdxi = r(k)
exit
end if
end do
gradf(i) = dfdxi
end do
! Print out the gradient
write(*,*) " "
write(*,*) " Grad(f(x)) = "
write(*,*) " "
do i = 1,n
write(*,*) gradf(i)
end do
end program gradient
In single precision it runs fine and gives me decent results. But when I try to change to double precision as shown in the code, I get an error when trying to compile claiming that the assignment statement
d(j) = ( f(n,xhup) - f(n,xhdown) ) / (2.d0*h)
is producing a type mismatch real(4)/real(8). I have tried several different declarations of double precision, appended every appropriate double precision constant in the code with d0, and I get the same error every time. I'm a little stumped as to how the function f is possibly producing a single precision number.
The problem is that f is not explicitely defined in your main program, therefore it is implicitly assumed to be of single precision, which is the type real(4) for gfortran.
I completely agree to the comment of High Performance Mark, that you really should use implicit none in all your fortran code, to make sure all object are explicitely declared. This way, you would have obtained a more appropriate error message about f not being explicitely defined.
Also, you could consider two more things:
Define your function within a module and import that module in the main program. It is a good practice to define all subroutines/functions within modules only, so that the compiler can make extra checks on number and type of the arguments, when you invoke the function.
You could (again in module) introduce a constant for the precicision and use it everywhere, where the kind of a real must be specified. Taking the example below, by changing only the line
integer, parameter :: dp = kind(1.0d0)
into
integer, parameter :: dp = kind(1.0)
you would change all your real variables from double to single precision. Also note the _dp suffix for the literal constants instead of the d0 suffix, which would automatically adjust their precision as well.
module accuracy
implicit none
integer, parameter :: dp = kind(1.0d0)
end module accuracy
module myfunc
use accuracy
implicit none
contains
function f(n,x)
integer :: n
real(dp) :: x(n), f
f = 0.5_dp * x(1)**5 + cos(x(2)) + log(x(3)) - sqrt(x(4))
end function f
end module myfunc
program gradient
use myfunc
implicit none
real(dp) :: x(n), xhup(n), xhdown(n), d(M), r(M), dfdxi, h0, h, gradf(n)
:
end program gradient
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