Carl Love

Carl Love

28035 Reputation

25 Badges

12 years, 320 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are answers submitted by Carl Love

Please try this reformatted version of your code. The only algorithmic change that I made is that I take the absolute value of the relative error term C. Your code didn't use absolute value, which I guessed was a mistake. I renamed 0.0001 as epsilon and 0.9 as fudge_factor. These can now be passed in as keyword parameters. That is, you can make the call as

Karmarkar(A,c);

which'll use the default values epsilon = 1e-4 and fudge_factor = 0.9, or you can make the call as, for example,

Karmarkar(A,c, epsilon= 1e-5, fudge_factor= 0.95);

Here's the code:

Karmarkar:= proc(
     A::Matrix(datatype= float[8]),
     c::Vector(datatype= float[8]),
     {epsilon::positive:= 1e-4},
     {fudge_factor::realcons:= 0.9}
)
uses LA= LinearAlgebra;
local
     n:= LA:-ColumnDimension(A),
     y:= Vector(n, fill= 1/n, datatype= float[8]),
     r:= evalf(1/sqrt(n*(n-1))),
     x_new:= `+`(LA:-NullSpace(A)[]),
     x,
     C:= epsilon,
     Ones:= Vector[row](n, fill= 1),
     J:= LA:-IdentityMatrix(n, datatype= float[8]),
     Diag, B, p
;
     while C >= epsilon do
          x:= x_new;
          Diag:= LA:-DiagonalMatrix(x/LA:-Norm(x, 1), datatype= float[8]);
          B:= <A.Diag, Ones>;
          p:= (J - B^+.(B.B^+)^(-1).B).(c.Diag)^+;
          p:= p/LA:-Norm(p,2);
          y:= y - fudge_factor*r*p;
          x_new:= Diag.y/(Ones.Diag.y);
          C:= abs(c.(x_new - x)/(c.x))
     end do;
     x_new
end proc;

There's no need for you to change the section-subsection arrangement of your program in order to use a module. You can define the procedures outside the module and just put their names in the module, like this

procA:= proc() (*...*) end proc:
procB:= proc() (*...*) end proc:

MyPackage:= module()
option package;
export
     procA:= eval(:-procA),
     procB:= eval(:-procB)
;
end module:

Arguments are not required for Int, int, or fsolve. So one way to handle this is

restart

f := proc (t) options operator, arrow; (-1)*4.44149345997579*(1/10000000000)*t^4+3.96767334279248*(1/10000000)*t^3+(-1)*0.136020090578339e-3*t^2+0.215218736996789e-1*t-0.329863673271032e-1 end proc:

iterf := unapply((250-Te)*1.30674818024691319-(Int(f, Te .. 250))-(Int(f, 0 .. Te)), Te):

fsolve(iterf, 50 .. 200);

53.63916000

(1)
 
 

Download wsCorr.mw

On the other hand, your function can be easily symbolically integrated, and the result of that can be easily symbolically solved, so you can change Int to int and do

restart

f := proc (t) options operator, arrow; (-1)*4.44149345997579*(1/10000000000)*t^4+3.96767334279248*(1/10000000)*t^3+(-1)*0.136020090578339e-3*t^2+0.215218736996789e-1*t-0.329863673271032e-1 end proc:

iterf := unapply((250-Te)*1.30674818024691319-(int(f, Te .. 250))-(int(f, 0 .. Te)), Te);

proc (Te) options operator, arrow; 70.0928747-1.306748180*Te end proc

(1)

solve(iterf(Te), {Te});

{Te = 53.63915999}

(2)

``

Download wsCorr2.mw

As mentioned by Kitonum, the sequence must be enclosed in square brackets rather than curly braces for this operation to make much sense.

a:= [10, 11, -13, -9, 20, 74, -10]:

The first way mentioned by Kitonum is fine for a list of numbers, but here is an alternative that also works for lists containing a mixture of simple symbolic and numeric entries:

evalindets[flat](a, negative, 0);

Update: The following is safer, in case the symbolic list entries contain embedded negatives:

map(x-> `if`(x::negative, 0, x), a);

Here's your program translated into Maple. You'll notice that it's much shorter than the Matlab version.



restart:

line:= proc(Pt1::[realcons,realcons], Pt2::[realcons,realcons])
global Lines;
     Lines[Pt1,Pt2]:= ()
end proc:

Point:= proc(x::realcons, y::realcons)
global Points;
     Points[x,y]:= ()
end proc:

Rand:= RandomTools:-Generate(float(range= 0..1, method= uniform), makeproc):

# Firstly, set the size limit for the grid, which shall define how many

# points there are in both the vertical and horizontal direction

size:= 40;


# Iteration through x, using the line function to create a number of

# horizontal lines up to the limit point

 

for x to size do  line([0, size], [x, x])  end do:

 

# Now iterating through the diagonals, using two sets of

# lines, both starting from the line going through the origin. The first

# iterates through the lines that pass through positive x values at y=0,

# the second iterates through the lines passing through negative x values

# at y=0

# d must be increased by 2 each time to ensure that equilateral triangles

# are formed.

 

for d from 0 by 2 to size do
     #Upward diagonals

     line([d, size], [0, size-d]); line([0, size-d], [d, size]);

     #Downward diagonals:

     line([d, 0], [0, d]); line([size, d], [d, size])

end do:

 

# The program now iterates through potential y values for the potential

# points. Then it tests the value of y to see what orientation the lattice

# is at that point, then randomly selects x values to enter, iterating

# between all the possible x values in the orientation before moving on to

# the next y value.

 

for y from 0.5 by 0.5 while y<size do
     (i,s):= `if`(frem(y,1)=.5, [0,1], `if`(frem(y,2)=1, [0,2], [1,2]))[];
     seq(`if`(Rand() > 0.5, Point(x,y), [][]), x= i..size-1, s)

end do:

40

(1)

plots:-display(
     [plot([indices(Lines)], thickness= 0, color= gray),
      plot(
          [indices(Points)],
          style= point, symbol= soliddiamond, symbolsize= 1, color= red
      )], gridlines= false
);

 

 

NULL


Download Lattice.mw

Looks like you have some hybrid Mathematica/Maple syntax. Maple uses round parentheses instead of square brackets. The command for extracting the real part of an expression is a combination of evalc and Re:

evalc(Re(sqrt(x+I*y)));

The evalc tells Maple to assume that all variables are real. The Re alone wouldn't return the above answer because that assumption wouldn't have yet been made.

Here is the algorithm coded in Maple and a test instance. Any advice on how I can do more of the Matrix operations inplace would be much appreciated.

 

Fuzzy C-Means Clustering

restart:

FuzzyCMeans:= proc(
     X::Matrix,   #The rows of X are the data points.
     #number of clusters and number of means:
     {clusters::And(posint, satisfies(x-> x > 1)):= 2},
     {fuzziness::satisfies(x-> x > 1):= 2},   #fuzziness factor
     {epsilon::positive:= 1e-4},   #convergence criterion
     {max_iters::posint:= 999},   #max number of iterations
     {Norm::procedure:= (x-> LinearAlgebra:-Norm(x,2))}
)
option `Written by Carl J Love, 2016-Apr-11`;
description
    "Fuzzy C-Means clustering algorithm.
     see http://home.deib.polimi.it/matteucc/Clustering/tutorial_html/cmeans.html
     and https://en.wikipedia.org/wiki/Fuzzy_clustering
    "
;
uses LA= LinearAlgebra;
local
     c:= clusters,     #number of clusrters and number of menas
     m:= fuzziness,    #fuzziness factor
     n:= op([1,1], X), #number of points
     d:= op([1,2], X), #dimension
     N:= Norm,
     #U[i,j] is the degree (on a 0..1 scale) to which point i belongs to cluster j.
     U:= Matrix((n,c), datatype= float[8]),
     #U1 is just an update copy of U.
     U1:= LA:-RandomMatrix((n,c), generator= 0..1, datatype= float[8]),
     C:= Matrix((c,d), datatype= float[8]), #The rows of C are the cluster centers.
     e:= 2/(m-1),
     i, j, k, jj, #loop indices
     UM # U^~m
;
     for jj to max_iters while LA:-Norm(U-U1, infinity) >= epsilon do
          U:= copy(U1);
          UM:= U^~m;
          for j to c do
               C[j,..]:= add(UM[i,j].X[i,..], i= 1..n) / add(UM[i,j], i= 1..n)
          end do;
          U1:= Matrix(
               (n,c),
               (i,j)-> 1/add((N(X[i,..]-C[j,..])/N(X[i,..]-C[k,..]))^e, k= 1..c),
               datatype= float[8]
          )
     end do;
     if jj > max_iters then error "Didn't converge" end if;
     userinfo(1, FuzzyCMeans, "Used", jj, "iterations.");
     (C,U1)                
end proc:

#Test data:
X:=
     [[5.37,19.50],[5.73,19.44],[4.66,20.03],[5.66,20.38],[4.22,21.97],
      [5.08,20.67],[5.08,19.08],[4.54,20.06],[4.35,19.82],[5.19,20.72],
      [4.48,19.95],[5.76,19.81],[4.15,18.68],[6.37,20.60],[5.58,21.13],
      [5.76,19.91],[5.85,19.02],[5.00,19.71],[5.42,20.31],[4.77,21.45],
      [8.61,19.48],[10.70,20.31],[10.99,20.28],[11.68,21.28],[9.12,20.77],
      [10.30,20.07],[10.40,21.62],[10.95,20.34],[9.79,20.29],[9.69,20.86],
      [10.02,21.45],[11.05,20.19],[9.20,17.96],[10.49,19.88],[9.61,19.49],
      [10.33,19.59],[9.29,20.94],[10.17,19.64],[10.97,20.32],[10.08,19.16]
     ]
:
XM:= Matrix(X, datatype= float[8]):


infolevel[FuzzyCMeans]:= 1:

(C,U):= FuzzyCMeans(
     XM,
     #All options are set to their default values here:
     clusters= 2, fuzziness= 2, epsilon= 1e-4, max_iters= 999,
     Norm= (x-> LinearAlgebra:-Norm(x,2))
);

FuzzyCMeans: Used 9 iterations.

 

C, U := Matrix(2, 2, {(1, 1) = 5.17624062133678, (1, 2) = 20.0938323603206, (2, 1) = 10.2161889439051, (2, 2) = 20.2331395528376}), Vector(4, {(1) = ` 40 x 2 `*Matrix, (2) = `Data Type: `*float[8], (3) = `Storage: `*rectangular, (4) = `Order: `*Fortran_order})

(1)

#Plot. First separate points into clusters:
(CL1,CL2):= selectremove(i-> U[i,1] > U[i,2], [$1..nops(X)]):
plots:-display(
     [plot(
          map(CL-> XM[CL,..], [CL1,CL2]), color= [red, green],
          style= point, symbol= diagonalcross, symbolsize= 16
      ),
      plot(
          `[]`~(convert(C, listlist)), color= [red, green],
          style= point, symbol= circle, symbolsize= 32
      )
     ], gridlines= false
 );

 

 

 

Download Fuzzy_clusters.mw

You want

plot(eval(C, k= k/K), k= 0*K..4*K, labels= ['K', 'C']);

 

You can't have more than one independent variable in an ODE system that is solved by dsolve. You have x and y as independent variables.

Use the bits option of Bits:-Split. For example,

mb:= Bits:-Split~(convert(message, bytes), bits= 8);

You need a multiplication sign:

g:= x-> exp(x^2*(x-a));

This is done by computing the exclusive-or (xor) of the two bit strings and counting the ones in the result.

CountOnes:= proc(n::nonnegint)
local q:= n, c:= 0;
     while q > 0 do  c:= c+irem(q,2,'q') end do;
     c
end proc:
 
CountFlips:= (X::{list, Matrix, Vector}, Y::{list, Matrix, Vector})->
     CountOnes(Bits:-Xor((Bits:-Join@convert)~([X,Y], list)[]))
:

CountFlips(<1,0,0,0,0,0,0,0>, <1,1,1,1,0,0,1,1>);

     5

Change your definition of B_interp to

B_interp:= (sr, e_g)->
     CurveFitting:-ArrayInterpolation(
          [SR, E_G], Vert_Coef, [[sr], [e_g]], method= linear
     )[1,1]
:

 

You want to use Matrices instead of subscripted names. It'll be much faster. Then your code will look like this:

restart:
dellT:= 0:  h:= 1:
tile:= Matrix(150$2, datatype= float[8]):
#You'll need to fill the above matrix with initial values.
tile2:= Matrix(tile):
to 20 do    
     for j from 2 to 149 do
          for k from 2 to 149 do  
               tile2[j,k]:= dellT/h^2*(tile[j+1,k]-4*tile[j,k]+tile[j-1,k]+tile[j,k-1])+tile[j,k]  
          end do
     end do;  
     tile:= copy(tile2)
end do:

Assuming that you'll be generating a lot of these pairs, you'll want to avoid regenerating the generating procedure, which is inefficient. This can be done with a module.

GenXY:= module()
local
     R:= RandomTools:-Generate(list(integer(range= 1..7), 2), makeproc),
     ModuleApply:= proc()
     local x:= 0, y:= 0;
          while x=y do  (x,y):= R()[]  end do;
          (min(x,y), max(x,y))
     end proc
;
end module:
     
(x,y):= GenXY();

                           
   2, 7


First 230 231 232 233 234 235 236 Last Page 232 of 395