(* Mathematica Package *) BeginPackage["LamDelosmeSA`", { "MultivariateStatistics`"}] (* Exported symbols added here with SymbolName::usage *) LamDelosmeSA::usage = "LamDelosmeSA[metric, variables] performs Lam-Delosme simulated annealing on a function given by metric. Format for variables is {name, low_end_of_estimated_range, high_end_of_estimated_range}." ldsa::init = "Failed to find valid intitialization in `1` tries."; Begin["`Private`"] (* Begin Private Context *) SetAttributes[LamDelosmeSA, HoldFirst]; DefaultNumForgetMoves = 10000; DefaultNumInitMoves = 10000; DefaultInitInverseTemp = 0; DefaultLambda = .01; DefaultMeanMemoryProduce = 600; DefaultStdDevMemoryProduce = 30000; DefaultEstimateUpdateFreq = 100; DefaultTemperUpdateFreq = 10; DefaultPercentOfRange = .03; DefaultReportingFunc = Report; DefaultMoveGenerator = ReinitzUpdate; DefaultStoppingCriterion = "DeltaMeanEnergy"; DefaultStoppingDeltaE = 10^-3; DefaultMaxFrozenIters = 3; DefaultSweepsThetaUpdate = 100; DefaultIntializeAttempts = 10^6; Options[LamDelosmeSA] = { InitialInverseTemp -> DefaultInitInverseTemp, NumForgetMoves -> DefaultNumForgetMoves, NumInitMoves -> DefaultNumInitMoves, Lambda -> DefaultLambda, MeanMemProd -> DefaultMeanMemoryProduce, StdDevMemProd -> DefaultStdDevMemoryProduce, EstimateUpdateFreq -> DefaultEstimateUpdateFreq, TemperatureUpdateFreq -> DefaultTemperUpdateFreq, MoveGenerator -> DefaultMoveGenerator, InitState -> {}, MaximumFrozenIterations -> DefaultMaxFrozenIters, InitialThetas -> {}, ReportFunc -> DoNothing, TalkativeInit -> False, TalkativeErrors -> False, UseSlaves -> False, MixingFrequency -> 10, StoppingCriterion -> DefaultStoppingCriterion, StoppingDeltaEnergy -> DefaultStoppingDeltaE, Debugging -> False, SweepsBetweenThetaUpdates -> DefaultSweepsThetaUpdate, InitializeTries -> DefaultIntializeAttempts }; LamDelosmeSA[metric_, variables_List, opts:OptionsPattern[]] := LamDelosmeSA[metric, variables, {True}, opts]; LamDelosmeSA[metric_, variables_List, hardConstraints_:{True}, OptionsPattern[]] := Module[{variableNames, estVariableRanges, initState, userInit, needsInit, initRest, state, thetas, energy, sum, sqrdSum, numInitMoves, totalNumMoves, estimateMean, estimateVrnc, estimateStDv, acceptRatio, lambda, estimateUpdateFreq, meanEstimator, stdvEstimator, s, deltaS, tempUpdateFreq, alpha, numTemp, numAccepted, keepRunning, maxFrozen, timesFrozen, bestEnergyEver, bestStateEver, initThetas,report, talkativeInit, talkativeErrs, constraint, moveGenerator, mixingIters, mean, deltaMean, oldMean, numParallelProcessors, estimateUpdateFreqEach, mmp, sdmp,variance, maxParallelProcessors,parSuccess,slaves, userSlaves, mixingFreq,stopCrit, stopDeltaEnergy, debug, allstats, acceptStats, emptyStats, thetaMin, thetaMax, updateTheta, gain, numForgetMoves, thetaUpdateSweeps, movesPerThetaUpdt, completedMoves, movesPerProcessor, movesPerUpdate, movesLeft, movesThisIteration, tsum, tsqrdSum, tnumAccepted}, If[OptionValue[UseSlaves], numParallelProcessors = Length[Parallel`Parallel`$Slaves]; Parallel`Parallel`ExportEnvironment[UpdateEstimator, Estimate, ReinitzUpdate, InitialRandomValue, InitializeVariables, InitializeThetas, parameterA, parameterB, Report, NewEstimator, initializationPeriod, sweep, DefaultNumInitMoves, DefaultLambda, DefaultMeanMemoryProduce, DefaultStdDevMemoryProduce, DefaultEstimateUpdateFreq, DefaultTemperUpdateFreq, DefaultPercentOfRange, DefaultReportingFunc, DefaultMaxFrozenIters, DefaultMoveGenerator, DefaultStoppingCriterion, DefaultStoppingDeltaE, forgettingPeriod, AddTrial, AddSuccess, DefaultInitInverseTemp, aggregateParallelStats, AccumulateStats, DefaultSweepsThetaUpdate, DefaultIntializeAttempts, ValidlyInitializeVariables];, (* else *) numParallelProcessors = 0 ]; (* True if we're in debugging mode. False otherwise. *) debug = If[OptionValue[Debugging], Print["debugging mode on."]; True, False, False]; (* List of the names of the variables we're optimizing. *) variableNames = Map[#[[1]]&, variables]; (* Approximate range over which to optimize each variable. *) estVariableRanges = Map[#[[1]] -> {#[[2]],#[[3]]}&, variables]; (* Single conjunction that encodes all of the hard constraints *) constraint = Fold[(#1 && #2)&, True, hardConstraints]; (* At the moment, the idea of a user-supplied initialization exists, but is poorly thought-out. Right here, what we have is that if we're using more than one processor we initialize all of the processors' states independently, but if we are using only one processor we allow the user to set some subset of the initial state. *) If[numParallelProcessors > 0, state = Table[ValidlyInitializeVariables[variableNames, estVariableRanges, constraint, OptionValue[InitializeTries]], {numParallelProcessors}];, (* else *) initState = OptionValue[InitState]; userInit = Cases[initState, (x_ -> y_) /; MemberQ[variableNames, x] ]; needsInit = Cases[variableNames, x_ /; ! MemberQ[Map[#[[1]] &, userInit], x]]; initRest = ValidlyInitializeVariables[needsInit, estVariableRanges, constraint, OptionValue[InitializeTries]]; state = Union[userInit, initRest]; ]; acceptStats = Map[(#1 -> Stats[0, 0])&, variableNames]; emptyStats = acceptStats; (* so we don't have to keep redoing the initialization *) (* Initialization for the theta values *) initThetas = OptionValue[InitialThetas]; userInit = Cases[initThetas, (x_ -> y_) /; MemberQ[variableNames, x]]; needsInit = Cases[variableNames, x_ /; ! MemberQ[Map[#[[1]] &, userInit], x]]; initRest = InitializeThetas[needsInit, estVariableRanges]; thetas = Union[userInit, initRest]; initThetas = thetas; thetaMin = 10^-5; (* Maybe this should be made a parameter? *) thetaMax = Map[#[[1]]->#[[2]]*(1/DefaultPercentOfRange)*10&,thetas]; gain = 3; (* Maybe this should be made a parameter? *) updateTheta[name_ -> theta_, stats_] := name->Min[updateTheta[theta, name/.stats], name /.thetaMax]; updateTheta[theta_?NumberQ, Stats[accepted_, hits_]] := Max[E^(Log[theta] + gain*((accepted/hits)-.44)), thetaMin]; stopCrit = OptionValue[StoppingCriterion]; stopDeltaEnergy = OptionValue[StoppingDeltaEnergy]; talkativeInit = OptionValue[TalkativeInit]; talkativeErrs = OptionValue[TalkativeErrors]; moveGenerator = OptionValue[MoveGenerator]; report = OptionValue[ReportFunc]; numInitMoves = OptionValue[NumInitMoves]; (* numInitMoves = (numInitMoves*Length[variableNames]);*) numForgetMoves = OptionValue[NumForgetMoves]; mixingFreq = OptionValue[MixingFrequency]; thetaUpdateSweeps = OptionValue[SweepsBetweenThetaUpdates]; movesPerThetaUpdt = Ceiling[(thetaUpdateSweeps*Length[variableNames]) / (* it's important for this to be a multiple of the number of processors. *) Max[1,numParallelProcessors]]*Max[1,numParallelProcessors]; If[debug, Print["reportFunction:<",report, "> talkativeInit:<", talkativeInit, ">"]; Print["testing your report function, with empty state, energy 1, 0 iterations."]; report[{}, 1, 0]; ]; If[!MatchQ[stopCrit, "DeltaMeanEnergy"] && !MatchQ[stopCrit, "AcceptRatio"], Print["Stopping criterion given is <", stopCrit, ">, which is neither DeltaMeanEnergy nor AcceptRatio.\n", "Defaulting to <" , DefaultStoppingCriterion, ">"]; stopCrit = DefaultStoppingCriterion; ]; s = OptionValue[InitialInverseTemp]; (* Perform the "forgetting" decorrelation steps *) completedMoves = 0; While[completedMoves < numForgetMoves, movesLeft = numForgetMoves - completedMoves; If[numParallelProcessors > 0, movesPerProcessor = Ceiling[Min[movesLeft,movesPerThetaUpdt]/numParallelProcessors]; movesPerUpdate = movesPerProcessor * numParallelProcessors; Parallel`Parallel`ExportEnvironment[moveGenerator, Evaluate[OptionValue[MoveGenerator]]]; Parallel`Parallel`ExportEnvironment[report, Evaluate[OptionValue[ReportFunc]]]; Module[{results,movesHolder,namesHolder,movegenHolder,thetasHolder,metricHolder,constraintHolder, talkErrHolder,talkInitHolder,invTempHolder,statsHolder}, (* OMFG, HAXX! I can't figure out a better way to get it to evaluate these variables & pass their *values* to the remote kernels. If you're thinking, 'just ExportEnv them,' then you clearly haven't looked at previous svn check-ins. *) results = ReleaseHold[ReplaceAll[Hold[Parallel`Evaluate`ParallelMap[forgettingPeriod[#,movesHolder,namesHolder,movegenHolder, thetasHolder,metricHolder,constraintHolder, talkErrHolder,talkInitHolder,invTempHolder,statsHolder]&, state]], {movesHolder->movesPerProcessor, namesHolder->variableNames,movegenHolder->moveGenerator, thetasHolder->thetas, metricHolder->metric, constraintHolder->constraint, talkErrHolder->talkativeErrs, talkInitHolder->talkativeInit,invTempHolder->s, statsHolder->emptyStats}]]; state = Map[#[[1]]&, results]; energy = Map[#[[2]]&, results]; allstats = Map[#[[3]]&, results]; acceptStats = Map[aggregateParallelStats[#, allstats]&, variableNames]; ], (* else *) movesPerUpdate = Min[movesLeft,movesPerThetaUpdt]; {state, energy, acceptStats} = forgettingPeriod[state, movesPerUpdate, variableNames, moveGenerator, thetas, metric, constraint, talkativeErrs, talkativeInit, s, emptyStats]; ]; thetas = Map[updateTheta[#, acceptStats]&, thetas]; completedMoves += movesPerUpdate; ]; totalNumMoves = completedMoves; numAccepted = sum = sqrdSum = 0; acceptStats = emptyStats; (* Perform the intialization steps *) completedMoves = 0; While[completedMoves < numInitMoves, movesLeft = numInitMoves - completedMoves; If[numParallelProcessors > 0, movesPerProcessor = Ceiling[Min[movesPerThetaUpdt, movesLeft]/numParallelProcessors]; movesPerUpdate = movesPerProcessor * numParallelProcessors; Module[{results,a,b,c,d,e,f,g,h,invTempH, statsH}, (* OMFG, HAXX! I can't figure out a better way to get it to evaluate these variables & pass their *values* to the remote kernels. If you're thinking, 'just ExportEnv them,' then you clearly haven't looked at previous svn check-ins. *) results = ReleaseHold[ReplaceAll[Hold[Parallel`Evaluate`ParallelMap[initializationPeriod[#,a,b,c,d,e,f,g,h, invTempH, statsH]&, state]], {a->movesPerProcessor, b->variableNames, c->moveGenerator, d->thetas, e->metric, f->constraint, g->talkativeErrs, h->talkativeInit, invTempH->s, statsH->emptyStats} ]]; state = Map[#[[1]]&, results]; sum += Total[Map[#[[2]]&, results]]; sqrdSum += Total[Map[#[[3]]&, results]]; energy = Map[#[[4]]&, results]; allstats = Map[#[[5]]&, results]; acceptStats = Map[aggregateParallelStats[#, allstats]&, variableNames]; numAccepted += Total[Map[#[[6]]&, results]]; ], (* else *) movesPerUpdate = Min[movesPerThetaUpdt, movesLeft]; {state, tsum, tsqrdSum, energy, acceptStats, tnumAccepted} = initializationPeriod[state, movesPerUpdate, variableNames, moveGenerator, thetas, metric, constraint, talkativeErrs, talkativeInit, s, emptyStats]; sum += tsum; sqrdSum += tsqrdSum; numAccepted += tnumAccepted; ]; thetas = Map[updateTheta[#, acceptStats]&, thetas]; completedMoves += movesPerUpdate; ]; totalNumMoves += completedMoves; estimateMean = sum/completedMoves; estimateVrnc = sqrdSum/completedMoves - estimateMean^2; (* floating point weirdness sometimes results in variances that should be 0 coming out negative *) If[estimateVrnc < 0, estimateVrnc = 0]; estimateStDv = Sqrt[estimateVrnc]; acceptRatio = numAccepted/completedMoves; If[debug, Print["sum : ", sum]; Print["sqrdSum : ", sqrdSum]; Print["completedMvs: ", completedMoves]; Print["estimateMean: ", estimateMean]; Print["estimateVrnc: ", estimateVrnc]; Print["estimateStdv: ", estimateStDv]; Print["acceptRatio : ", acceptRatio]; ]; lambda = OptionValue[Lambda]; estimateUpdateFreq = OptionValue[EstimateUpdateFreq]; (* estimateUpdateFreq = (estimateUpdateFreq*Length[variableNames]);*) If[numParallelProcessors > 0, estimateUpdateFreqEach = Ceiling[estimateUpdateFreq/numParallelProcessors]; estimateUpdateFreq = numParallelProcessors*estimateUpdateFreqEach;, (*else*) estimateUpdateFreqEach = estimateUpdateFreq; ]; mmp = OptionValue[MeanMemProd]; meanEstimator = NewEstimator[mmp, estimateUpdateFreq, lambda, estimateMean, estimateVrnc/(estimateMean^2)]; sdmp = OptionValue[StdDevMemProd]; stdvEstimator = NewEstimator[sdmp, estimateUpdateFreq, lambda, estimateStDv, estimateStDv/estimateMean]; alpha = 4 * acceptRatio * ((1-acceptRatio)/(2-acceptRatio))^2; deltaS = .5/estimateStDv; If[debug, Print["deltaS: ", deltaS]; ]; tempUpdateFreq = OptionValue[TemperatureUpdateFreq]; numTemp = 0; keepRunning = True; maxFrozen = OptionValue[MaximumFrozenIterations]; timesFrozen = 0; bestEnergyEver = Infinity; bestStateEver = {}; mixingIters = 0; mean = estimateMean; variance = estimateVrnc; completedMoves = 0; deltaMean = 0; numAccepted = sum = sqrdSum = 0; While[keepRunning, movesThisIteration = Min[estimateUpdateFreq-Mod[completedMoves,estimateUpdateFreq], movesPerThetaUpdt -Mod[completedMoves,movesPerThetaUpdt ]]; Module[{ratio, a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,statsH,numProcH,printablestats}, If[numParallelProcessors > 0, If[debug, Print["s<", s, "> deltaS<", deltaS, ">"]; Print["eststddv<", Estimate[stdvEstimator, s], "> estmean<", Estimate[meanEstimator, s], ">"]; ]; Module[{results}, results = ReleaseHold[ReplaceAll[Hold[Parallel`Evaluate`ParallelMap[sweep[#[[1]], #[[2]], o, a,b,c,d,e,f,g,h,i,j,k,l,m,n,p,statsH,numProcH ]&, Thread[{state, energy}]]], {a->meanEstimator, b->stdvEstimator, c->variableNames, d->moveGenerator, e->thetas, f->constraint, g->metric, h->talkativeErrs, i->deltaS, j->numTemp, k->tempUpdateFreq, l->lambda, m->alpha, n->movesThisIteration/numParallelProcessors, o->s, p->estimateMean,statsH->emptyStats,numProcH->numParallelProcessors} ]]; state = Map[#[[1]]&, results]; sum += Total[Map[#[[2]]&, results]]; sqrdSum += Total[Map[#[[3]]&, results]]; energy = Map[#[[4]]&, results]; numAccepted += Total[Map[#[[5]]&, results]]; (* computation of these is deterministic, so we'll just take the one from the first processor. *) s = results[[1,6]]; deltaS = results[[1,7]]; allstats = Append[Map[#[[8]]&, results],acceptStats]; acceptStats = Map[aggregateParallelStats[#, allstats]&, variableNames]; numTemp = tempUpdateFreq - Mod[(movesThisIteration/numParallelProcessors)-numTemp, tempUpdateFreq]; ], (* else *) {state, tsum, tsqrdSum, energy, tnumAccepted, s, deltaS, acceptStats} = sweep[state, energy, s, meanEstimator, stdvEstimator, variableNames, moveGenerator, thetas, constraint, metric, talkativeErrs, deltaS, numTemp, tempUpdateFreq, lambda, alpha, movesThisIteration, estimateMean, acceptStats, 1]; sum += tsum; sqrdSum += tsqrdSum; numAccepted += tnumAccepted; numTemp = tempUpdateFreq - Mod[movesThisIteration-numTemp, tempUpdateFreq]; ]; completedMoves += movesThisIteration; totalNumMoves += movesThisIteration; (* do things that happen some multiple of every TAU updates *) If[Mod[completedMoves, estimateUpdateFreq]==0, If[numParallelProcessors > 0, mixingIters++; If[mixingIters >= mixingFreq, Module[{boltzmannFactors, total, probs, sepairs, matters, lowestEnergy, lowestEposit, th, keep, energies, states}, matters = Map[-#*s > Log[$MinNumber]&, energy]; If[matters == Table[False, {numParallelProcessors}], lowestEnergy = Min[energy]; lowestEposit = Position[energy, lowestEnergy][[1,1]]; state = Table[Part[state,lowestEposit], {numParallelProcessors}]; energy = Table[lowestEnergy, {numParallelProcessors}];, (*else*) th = Thread[{matters, state, energy}]; keep = Cases[th, {mm_,ss_,ee_} /; mm]; energies = Map[#[[3]]&, keep]; states = Map[#[[2]]&, keep]; boltzmannFactors = Map[E^(Max[-#*s,Log[$MinNumber]+1])&, energies]; total = Total[boltzmannFactors]; probs = Map[#/total&, boltzmannFactors]; sepairs = Table[RandomChoice[probs->Thread[{states, energies}]], {numParallelProcessors}]; state = Map[#[[1]]&, sepairs]; energy = Map[#[[2]]&, sepairs]; ]; ]; mixingIters = 0; ]; ]; oldMean = mean; mean = sum / estimateUpdateFreq; variance = sqrdSum / estimateUpdateFreq; acceptRatio = numAccepted / estimateUpdateFreq; numAccepted = sqrdSum = sum = 0; deltaMean = Abs[mean - oldMean]; If[MatchQ[stopCrit, "AcceptRatio"] && acceptRatio == 0, timesFrozen++, (* else *) If[MatchQ[stopCrit, "DeltaMeanEnergy"] && deltaMean < stopDeltaEnergy, timesFrozen++, timesFrozen = 0 ];, (* fail! *) Print["This shouldn't happen: neither stopping criterion?"]; ]; If[timesFrozen == maxFrozen, keepRunning = False ]; If[debug, Print["mean: ", mean]; Print["vrnc: ", variance]; Print["s : ", s]; ]; meanEstimator = UpdateEstimator[meanEstimator, s, mean]; If[variance > 0, stdvEstimator = UpdateEstimator[stdvEstimator, s, Sqrt[variance]]; ]; estimateMean = Estimate[meanEstimator, s]; If[MatchQ[estimateMean,Indeterminate], Print[meanEstimator]; Abort[]; ]; estimateStDv = Estimate[stdvEstimator, s]; ratio = (1-acceptRatio)/(2-acceptRatio); alpha = 4 * acceptRatio * ratio^2; ]; printablestats = acceptStats; (* do things that happen some multiple of every theta-update-cycle updates *) If[Mod[completedMoves, movesPerThetaUpdt]==0, thetas = Map[updateTheta[#, acceptStats]&, thetas]; acceptStats = emptyStats; ]; (* might as well just always do this stuff *) Module[{lowestEnergy, lowestEposit, lowestEState}, If[MatchQ[energy, _List], lowestEnergy = Min[energy]; lowestEposit = Position[energy, lowestEnergy][[1,1]]; lowestEState = Part[state,lowestEposit];, (* else *) lowestEnergy = energy; lowestEState = state; ]; If[lowestEnergy < bestEnergyEver, bestEnergyEver = lowestEnergy; bestStateEver = lowestEState; report[bestStateEver, bestEnergyEver, (totalNumMoves)]; ]; ]; If[debug, Print["iter<",completedMoves,"> mean<", mean, "> dM<", deltaMean, ">" ]; Print["S<", s, "> aR<", acceptRatio, ">"]; Module[{ma, la}, ma = Fold[If[#1[[2, 1]]/Max[1,#1[[2, 2]]] > #2[[2, 1]]/Max[1,#2[[2, 2]]], #1, #2] &, First[printablestats], Rest[printablestats]]; la = Fold[If[#1[[2, 1]]/Max[1,#1[[2, 2]]] < #2[[2, 1]]/Max[1,#2[[2, 2]]], #1, #2] &, First[printablestats], Rest[printablestats]]; Print["most <", ma, ">\nleast<", la, ">"]; ]; ]; ]; ]; Module[{lowestEnergy, lowestEposit, lowestEState}, If[MatchQ[energy, _List], lowestEnergy = Min[energy]; lowestEposit = Position[energy, lowestEnergy][[1,1]]; lowestEState = Part[state, lowestEposit];, (* else *) lowestEnergy = energy; lowestEState = state; ]; {{lowestEnergy, lowestEState}, {bestEnergyEver, bestStateEver}, totalNumMoves} ] ]; Report[state_, energy_, iter_] := Module[{}, Print["New best energy ever: <", energy, "> at iter <",iter,">\n<", state, ">"]; ]; NewEstimator[prod_, freq_, lambda_, invY_, pA_] := Module[{y,z}, y = 1/invY; z = (freq/(prod/lambda)); Estimator[Max[10^-10, 1-z], 1 , 0 , 0, 0, y, y^2 , pA, y] ]; parameterA[e_Estimator] := e[[8]]; parameterB[e_Estimator] := e[[9]]; InitializeThetas[names_, ranges_] := MapThread[#1->(DefaultPercentOfRange * (Max[#2]-Min[#2]))&, {names, names /. ranges}]; ValidlyInitializeVariables[variableNames_, variableRanges_, constraint_, tries_] := Module[{state, tried=0}, state = InitializeVariables[variableNames, variableRanges]; While[tried < tries && !(constraint /. state), state = InitializeVariables[variableNames, variableRanges]; ]; If[tried == tries && !(constraint /. state), Message[ldsa::init, tries] ]; state ]; InitializeVariables[variableNames_, variableRanges_] := Map[InitialRandomValue[#, (# /. variableRanges)]&, variableNames]; InitialRandomValue[name_, {min_, max_}] := (name -> RandomReal[UniformDistribution[{min,max}]]); ReinitzUpdate[name_, current_, theta_] := current + (RandomChoice[{1,-1}]*theta*Log[RandomReal[]]); Estimate[estimator_Estimator, temp_] := Module[{denom}, denom = ((parameterA[estimator] * temp) + parameterB[estimator]); If[denom == 0, Print["got denominator 0. temperature is <", temp ,"> here is the estimator"]; Print[FullForm[estimator]]; 10^30 (* i dunno, some big value? *), (* else *) 1/denom, (* if the comparison fails, then ... yeah, i've got no idea then. *) Print["could not compare denominator <", denom, "> to 0. temperature is <", temp ,"> here is the estimator"]; Print[FullForm[estimator]]; -1 ] ]; UpdateEstimator[estimator_Estimator, temp_, invY_] := Module[{y, weight, sum, sumXX, sumXY, sumX, sumY, sumYY, pa, pb}, y = 1/invY; weight = estimator[[1]]; sum = estimator[[2]] * weight + 1 ; sumXX = estimator[[3]] * weight + temp^2; sumXY = estimator[[4]] * weight + temp*y; sumX = estimator[[5]] * weight + temp; sumY = estimator[[6]] * weight + y; sumYY = estimator[[7]] * weight + y^2; If[MemberQ[Map[realQ[#]&, {sum, sumXX, sumXY, sumX, sumY, sumYY}], False], Print["boo: ", {sum, sumXX, sumXY, sumX, sumY, sumYY, temp, invY}]; Abort[]; ]; pa = (sum * sumXY - sumX * sumY)/Max[(sum * sumXX - sumX^2),10^-30]; pb = (sumY - pa * sumX)/sum; Estimator[weight, sum, sumXX, sumXY, sumX, sumY, sumYY, pa, pb] ]; forgettingPeriod[startLocalState_, numForgottenMovesEach_, variableNames_, moveGenerator_, thetas_, metric_, constraint_, talkativeErrs_, talkativeInit_, forgettingInvTemp_, stats_] := Module[ {iter, whoseTurn, oldVal, newVal, var, localstats, varStat, nVarStat, plocalState, localState, plocalEnergy, localEnergy, deltaEnergy}, localstats = stats; localState = startLocalState; localEnergy = metric /. localState; For[iter = 0, iter < numForgottenMovesEach, iter++, whoseTurn = Mod[iter, Length[variableNames]] + 1; var = variableNames[[whoseTurn]]; varStat = var /. localstats; nVarStat = AddTrial[varStat]; oldVal = var /. localState; newVal = moveGenerator[var, oldVal, var /. thetas]; plocalState = ReplaceAll[localState, (var -> oldVal) -> (var -> newVal)]; localstats = ReplaceAll[localstats, (var -> varStat) -> (var -> nVarStat)]; If[ constraint /. plocalState, plocalEnergy = metric /. plocalState; If[ (talkativeErrs && !NumberQ[localEnergy]), Print["Got an energy that wasn't a number (during forgetting)."]; Print["Tried to change <", variableNames[[whoseTurn]], "> from <", oldVal, "> to <", newVal,">. Got <",plocalEnergy,">"]; ]; deltaEnergy = plocalEnergy - localEnergy; If[ deltaEnergy <= 0 || (deltaEnergy*-forgettingInvTemp > Log[$MinNumber] && RandomReal[] <= E^(deltaEnergy*-forgettingInvTemp)), localState = plocalState; localEnergy = plocalEnergy; localstats = ReplaceAll[localstats, (var -> nVarStat) -> (var -> AddSuccess[nVarStat])]; ]; ]; (* If[ talkativeInit && Mod[iter, Floor[numForgottenMovesEach/10]]==0, Print["Working hard. Forgetting iter: ", iter]; ];*) ]; If[ talkativeInit, Print["Working hard. Forgetting iter: ", iter]; If[numForgottenMovesEach == 0, Print["Dude, check your damn math."]; ]; ]; {localState, localEnergy, localstats} ]; initializationPeriod[startLocalState_, numInitMovesEach_, variableNames_, moveGenerator_, thetas_, metric_, constraint_, talkativeErrs_, talkativeInit_, initializationInvTemp_, stats_] := Module[ {iter, whoseTurn, oldVal, newVal, lSum, lSqrdSum, localstats, var, varStat, nVarStat, deltaEnergy, numAccepted, plocalState, localState, plocalEnergy, localEnergy}, localstats = stats; lSum = lSqrdSum = 0; localState = startLocalState; localEnergy = metric /. localState; numAccepted = 0; For[iter = 0, iter < numInitMovesEach, iter++, whoseTurn = Mod[iter, Length[variableNames]] + 1; var = variableNames[[whoseTurn]]; varStat = var /. localstats; nVarStat = AddTrial[varStat]; oldVal = var/. localState; newVal = moveGenerator[var, oldVal, var /. thetas]; plocalState = ReplaceAll[localState, (var -> oldVal) -> (var -> newVal) ]; localstats = ReplaceAll[localstats, (var -> varStat) -> (var -> nVarStat)]; If[ constraint /. plocalState, plocalEnergy = metric /. plocalState; If[ (talkativeErrs && !NumberQ[localEnergy]), Print["Got an energy that wasn't a number (during initialization)."]; Print["Tried to change <", variableNames[[whoseTurn]], "> from <", oldVal, "> to <", newVal,">. Got<",plocalEnergy,">"]; ]; deltaEnergy = plocalEnergy - localEnergy; If[ deltaEnergy <= 0 || (deltaEnergy*-initializationInvTemp > Log[$MinNumber] && RandomReal[] <= E^(deltaEnergy*-initializationInvTemp)), localState = plocalState; localEnergy = plocalEnergy; localstats = ReplaceAll[localstats, (var -> nVarStat) -> (var -> AddSuccess[nVarStat])]; numAccepted++; ]; ]; lSum += localEnergy; lSqrdSum += localEnergy^2; (* If[ talkativeInit && Mod[iter, Floor[numInitMovesEach/10]]==0, Print["Working hard. Iter: ", iter]; ];*) ]; If[ talkativeInit, Print["Working hard. Iter: ", iter]; ]; {localState, lSum, lSqrdSum, localEnergy, localstats, numAccepted} ]; sweep[startLocalState_, startLocalEnergy_, startTemp_, meanEstimator_, stdvEstimator_, variableNames_, moveGenerator_, thetas_, constraint_, metric_, talkativeErrs_, startDS_, startNumTemp_, tempUpdateFreq_, lambda_, alpha_, estimateUpdateFreqEach_, emn_, stats_, numProcessors_] := Module[{estmtCounter, propState, newEnergy, energyChange, mean, variance, ratio, oldVal, newVal, whoseTurn, lSum, lSqrdSum, localState, localEnergy, lNumAccepted, s, estimateMean, estimateStDv, deltaS, numTemp, localstats, var, varStat, nVarStat}, localstats = stats; s = startTemp; deltaS = startDS; numTemp = startNumTemp; estimateMean = emn; localState = startLocalState; localEnergy = startLocalEnergy; lSum = lSqrdSum = lNumAccepted = 0; For[estmtCounter=0, estmtCounter < estimateUpdateFreqEach , estmtCounter++, whoseTurn = Mod[estmtCounter, Length[variableNames]] + 1; var = variableNames[[whoseTurn]]; varStat = var /. localstats; nVarStat = AddTrial[varStat]; oldVal = var/. localState; newVal = moveGenerator[var, oldVal, var /. thetas]; propState = ReplaceAll[localState, (var -> oldVal) -> (var -> newVal) ]; localstats = ReplaceAll[localstats, (var -> varStat) -> (var -> nVarStat)]; If[ constraint /. propState, newEnergy = metric /. propState; If[!NumberQ[newEnergy], If[talkativeErrs, Print["Got an energy that wasn't a number (during annealing).\nTried to change <", var, "> from <", oldVal, "> to <", newVal,">."]; ], (* else *) energyChange = newEnergy - localEnergy; If[energyChange < 0 || (-s*energyChange > Log[$MinNumber] && E^(-s*energyChange) > RandomReal[]), localState = propState; localEnergy = newEnergy; localstats = ReplaceAll[localstats, (var -> nVarStat) -> (var -> AddSuccess[nVarStat])]; lNumAccepted++; ]; ]; ]; lSum += localEnergy; lSqrdSum += (localEnergy - estimateMean)^2; If[MatchQ[lSqrdSum,Indeterminate], Print["booooooooooooooooooo"]; Print[lSum, " ", localEnergy, " ", estimateMean]; Abort[]; ]; If[--numTemp <= 0, s += (deltaS * numProcessors); estimateMean = Estimate[meanEstimator, s]; estimateStDv = Estimate[stdvEstimator, s]; deltaS = lambda * (alpha / (s^2 * estimateStDv^3)) * tempUpdateFreq; numTemp = tempUpdateFreq; ]; ]; {localState, lSum, lSqrdSum, localEnergy, lNumAccepted, s, deltaS, localstats} ]; AddTrial[Stats[successes_, trials_]] := Stats[successes, trials+1]; AddSuccess[Stats[successes_, trials_]] := Stats[successes+1, trials]; AccumulateStats[stl_] := Fold[(Stats[#1[[1]] + #2[[1]], #1[[2]] + #2[[2]]]) &, Stats[0, 0], stl]; aggregateParallelStats[vrblNm_, statsList_] := Module[{allstats}, allstats = Map[(vrblNm /. #)&, statsList]; (vrblNm -> AccumulateStats[allstats]) ]; realQ[x_] := NumberQ[x] && ! MatchQ[x, _Complex]; End[]; (* End Private Context *) EndPackage[];