15#include "mlir/Dialect/Arith/IR/Arith.h"
16#include "mlir/Dialect/Func/IR/FuncOps.h"
17#include "mlir/Dialect/Math/IR/Math.h"
36 assert(values.size() == 18 &&
"Expected 18 NUTSTreeState fields");
37 return {.q_left = values[0],
39 .grad_left = values[2],
42 .grad_right = values[5],
43 .q_proposal = values[6],
44 .grad_proposal = values[7],
45 .U_proposal = values[8],
46 .H_proposal = values[9],
49 .turning = values[12],
50 .diverging = values[13],
51 .sum_accept_probs = values[14],
52 .num_proposals = values[15],
58 SmallVector<Type> types;
60 types.push_back(val.getType());
65 StringRef label,
bool debugDump) {
67 return enzyme::DumpOp::create(builder, loc, value.getType(), value,
68 builder.getStringAttr(label))
76 RankedTensorType matrixType) {
77 assert(matrixType.getRank() == 2 &&
"Expected 2D tensor type");
78 assert(matrixType.getShape()[0] == matrixType.getShape()[1] &&
79 "Expected square matrix type");
81 int64_t size = matrixType.getShape()[0];
82 auto elemType = matrixType.getElementType();
84 SmallVector<Attribute> values;
85 values.reserve(size * size);
86 for (int64_t i = 0; i < size; ++i) {
87 for (int64_t j = 0; j < size; ++j) {
88 double val = (i == j) ? 1.0 : 0.0;
89 values.push_back(builder.getFloatAttr(elemType, val));
93 auto denseAttr = DenseElementsAttr::get(matrixType, values);
94 return arith::ConstantOp::create(builder, loc, matrixType, denseAttr);
99 RankedTensorType matrixType) {
100 assert(matrixType.getRank() == 2 &&
"Expected 2D tensor type");
101 assert(matrixType.getShape()[0] == matrixType.getShape()[1] &&
102 "Expected square matrix type");
104 int64_t size = matrixType.getShape()[0];
105 auto elemType = matrixType.getElementType();
107 SmallVector<Attribute> values;
108 values.reserve(size * size);
109 for (int64_t i = 0; i < size; ++i) {
110 for (int64_t j = 0; j < size; ++j) {
111 double val = (j == size - 1 - i) ? 1.0 : 0.0;
112 values.push_back(builder.getFloatAttr(elemType, val));
116 auto denseAttr = DenseElementsAttr::get(matrixType, values);
117 return arith::ConstantOp::create(builder, loc, matrixType, denseAttr);
123 auto matrixType = cast<RankedTensorType>(matrix.getType());
127 auto PA = impulse::DotOp::create(
128 builder, loc, matrixType, P, matrix, builder.getDenseI64ArrayAttr({}),
129 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({1}),
130 builder.getDenseI64ArrayAttr({0}));
133 return impulse::DotOp::create(
134 builder, loc, matrixType, PA, P, builder.getDenseI64ArrayAttr({}),
135 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({1}),
136 builder.getDenseI64ArrayAttr({0}));
140 Value invMass, Value momentum,
141 RankedTensorType positionType) {
146 auto invMassType = cast<RankedTensorType>(invMass.getType());
148 if (invMassType.getRank() == 1) {
151 impulse::ReshapeOp::create(builder, loc, positionType, invMass);
152 return arith::MulFOp::create(builder, loc, diagMass, momentum);
153 }
else if (invMassType.getRank() == 2) {
155 return impulse::DotOp::create(
156 builder, loc, positionType, momentum, invMass,
157 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({}),
158 builder.getDenseI64ArrayAttr({1}), builder.getDenseI64ArrayAttr({0}));
161 emitError(loc,
"ProbProg: Provided invMass must have rank 1 or 2, got rank " +
162 std::to_string(invMassType.getRank()));
167 Value momentum, Value invMass,
168 RankedTensorType positionType) {
169 auto elemType = positionType.getElementType();
170 auto scalarType = RankedTensorType::get({}, elemType);
172 auto halfConst = arith::ConstantOp::create(
173 builder, loc, scalarType,
174 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.5)));
182 auto pDotV = impulse::DotOp::create(
183 builder, loc, scalarType, momentum, v, builder.getDenseI64ArrayAttr({}),
184 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({0, 1}),
185 builder.getDenseI64ArrayAttr({0, 1}));
187 return arith::MulFOp::create(builder, loc, halfConst, pDotV);
192 RankedTensorType positionType) {
197 auto invMassType = cast<RankedTensorType>(invMass.getType());
198 auto elemType = invMassType.getElementType();
200 if (invMassType.getRank() == 1) {
202 auto sqrtInvMass = math::SqrtOp::create(builder, loc, invMass);
203 auto onesVector = arith::ConstantOp::create(
204 builder, loc, invMassType,
205 DenseElementsAttr::get(invMassType,
206 builder.getFloatAttr(elemType, 1.0)));
207 return arith::DivFOp::create(builder, loc, onesVector, sqrtInvMass);
215 impulse::CholeskyOp::create(builder, loc, invMassType, reversedInvMass,
216 builder.getBoolAttr(
true));
219 auto massMatrixSqrt = impulse::TriangularSolveOp::create(
220 builder, loc, invMassType, massMatrixSqrtInvT, identityMatrix,
221 builder.getBoolAttr(
true),
222 builder.getBoolAttr(
false),
223 builder.getBoolAttr(
false),
225 impulse::TransposeAttr::get(builder.getContext(),
226 impulse::Transpose::TRANSPOSE));
228 return massMatrixSqrt;
232std::pair<Value, Value>
234 Value invMass, Value massMatrixSqrt,
235 RankedTensorType positionType,
bool debugDump) {
236 auto elemType = positionType.getElementType();
237 auto scalarType = RankedTensorType::get({}, elemType);
239 auto zeroConst = arith::ConstantOp::create(
240 builder, loc, scalarType,
241 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
242 auto oneConst = arith::ConstantOp::create(
243 builder, loc, scalarType,
244 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
246 rng =
conditionalDump(builder, loc, rng,
"sampleMomentum: input rng state",
250 auto randomOp = impulse::RandomOp::create(
251 builder, loc, TypeRange{rng.getType(), positionType}, rng, zeroConst,
253 impulse::RngDistributionAttr::get(builder.getContext(),
254 impulse::RngDistribution::NORMAL));
256 auto rngOut = randomOp.getOutputRngState();
257 auto eps = randomOp.getResult();
259 if (!massMatrixSqrt) {
260 return {eps, rngOut};
263 auto massMatrixSqrtType = cast<RankedTensorType>(massMatrixSqrt.getType());
265 if (massMatrixSqrtType.getRank() == 1) {
268 impulse::ReshapeOp::create(builder, loc, positionType, massMatrixSqrt);
269 auto p = arith::MulFOp::create(builder, loc, diagSqrt, eps);
273 auto p = impulse::DotOp::create(
274 builder, loc, positionType, eps, massMatrixSqrt,
275 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({}),
276 builder.getDenseI64ArrayAttr({1}), builder.getDenseI64ArrayAttr({1}));
282 Value position2d, Value fullTrace,
285 cast<RankedTensorType>(ctx.
stepSize.getType()).getElementType();
287 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
288 auto c0 = arith::ConstantOp::create(
289 builder, loc, i64TensorType,
290 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
292 Value result = fullTrace;
293 for (
const auto &info : ctx.
supports) {
294 auto sliceType = RankedTensorType::get({1, info.size}, elemType);
295 auto posOffset = arith::ConstantOp::create(
296 builder, loc, i64TensorType,
297 DenseElementsAttr::get(i64TensorType,
298 builder.getI64IntegerAttr(info.offset)));
299 SmallVector<Value> extractIndices{c0, posOffset};
300 auto slice = impulse::DynamicSliceOp::create(
301 builder, loc, sliceType, position2d, extractIndices,
302 builder.getDenseI64ArrayAttr({1, info.size}));
304 auto traceOffset = arith::ConstantOp::create(
305 builder, loc, i64TensorType,
306 DenseElementsAttr::get(i64TensorType,
307 builder.getI64IntegerAttr(info.traceOffset)));
308 SmallVector<Value> updateIndices{c0, traceOffset};
309 result = impulse::DynamicUpdateSliceOp::create(
310 builder, loc,
traceType, result, slice, updateIndices);
318 cast<RankedTensorType>(ctx.
stepSize.getType()).getElementType();
319 auto positionType2d = RankedTensorType::get({1, ctx.
positionSize}, elemType);
320 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
321 auto c0 = arith::ConstantOp::create(
322 builder, loc, i64TensorType,
323 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
325 auto zeroConst = arith::ConstantOp::create(
326 builder, loc, positionType2d,
327 DenseElementsAttr::get(positionType2d,
328 builder.getFloatAttr(elemType, 0.0)));
329 Value result = zeroConst;
330 for (
const auto &info : ctx.
supports) {
331 auto sliceType = RankedTensorType::get({1, info.size}, elemType);
332 auto traceOffset = arith::ConstantOp::create(
333 builder, loc, i64TensorType,
334 DenseElementsAttr::get(i64TensorType,
335 builder.getI64IntegerAttr(info.traceOffset)));
336 SmallVector<Value> extractIndices{c0, traceOffset};
337 auto slice = impulse::DynamicSliceOp::create(
338 builder, loc, sliceType, fullTrace, extractIndices,
339 builder.getDenseI64ArrayAttr({1, info.size}));
341 auto posOffset = arith::ConstantOp::create(
342 builder, loc, i64TensorType,
343 DenseElementsAttr::get(i64TensorType,
344 builder.getI64IntegerAttr(info.offset)));
345 SmallVector<Value> updateIndices{c0, posOffset};
346 result = impulse::DynamicUpdateSliceOp::create(
347 builder, loc, positionType2d, result, slice, updateIndices);
354 Value position, Value rng,
360 auto gradSeed = arith::ConstantOp::create(
361 builder, loc, scalarType,
362 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
365 auto flatType = RankedTensorType::get({ctx.
positionSize}, elemType);
366 Value autodiffPosition = position;
367 auto autodiffPositionType = positionType;
368 auto autodiffGradType = positionType;
369 if (isCustomLogpdf) {
371 impulse::ReshapeOp::create(builder, loc, flatType, position);
372 autodiffPositionType = flatType;
373 autodiffGradType = flatType;
376 SmallVector<Value> autodiffInputs{autodiffPosition, gradSeed};
377 SmallVector<NamedAttribute> adAttrs{
378 builder.getNamedAttr(
380 builder.getArrayAttr({enzyme::ActivityAttr::get(
381 builder.getContext(), enzyme::Activity::enzyme_active)})),
382 builder.getNamedAttr(
384 builder.getArrayAttr(
385 {enzyme::ActivityAttr::get(builder.getContext(),
386 enzyme::Activity::enzyme_active),
387 enzyme::ActivityAttr::get(builder.getContext(),
388 enzyme::Activity::enzyme_const)})),
392 adAttrs.push_back(attr);
394 auto autodiffOp = enzyme::AutoDiffRegionOp::create(
395 builder, loc, TypeRange{scalarType, rng.getType(), autodiffGradType},
396 autodiffInputs, adAttrs);
398 Block *autodiffBlock = builder.createBlock(&autodiffOp.getBody());
399 autodiffBlock->addArgument(autodiffPositionType, loc);
401 builder.setInsertionPointToStart(autodiffBlock);
402 Value qArg = autodiffBlock->getArgument(0);
404 if (isCustomLogpdf) {
405 SmallVector<Value> callArgs;
406 callArgs.push_back(qArg);
408 auto callOp = func::CallOp::create(builder, loc, ctx.
logpdfFn,
409 TypeRange{scalarType}, callArgs);
410 Value U = arith::NegFOp::create(builder, loc, callOp.getResult(0));
412 enzyme::YieldOp::create(builder, loc, {U, rng});
421 SmallVector<Value> generateInputs;
422 generateInputs.push_back(rng);
425 SmallVector<Type> generateResultTypes;
426 generateResultTypes.push_back(
traceType);
427 generateResultTypes.push_back(scalarType);
431 auto generateOp = impulse::GenerateOp::create(
432 builder, loc, generateResultTypes, ctx.
fn, generateInputs, fullTrace,
436 arith::NegFOp::create(builder, loc, generateOp.getWeight());
437 Value jacobianCorrection =
440 arith::SubFOp::create(builder, loc, negWeight, jacobianCorrection);
442 SmallVector<Value> yieldValues{U, generateOp.getResult(2)};
443 enzyme::YieldOp::create(builder, loc, yieldValues);
446 builder.setInsertionPointAfter(autodiffOp);
448 Value grad = autodiffOp.getResult(2);
449 if (isCustomLogpdf) {
450 grad = impulse::ReshapeOp::create(builder, loc, positionType, grad);
454 autodiffOp.getResult(0),
456 autodiffOp.getResult(1)
463 Value rng, Value direction,
469 auto negStepSize = arith::NegFOp::create(builder, loc, ctx.
stepSize);
470 Value signedStepSize = impulse::SelectOp::create(
471 builder, loc, scalarType, direction, ctx.
stepSize, negStepSize);
473 auto halfConst = arith::ConstantOp::create(
474 builder, loc, scalarType,
475 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.5)));
477 ArrayRef<int64_t> shape = positionType.getShape();
478 auto stepSizeBroadcast =
479 BroadcastOp::create(builder, loc, positionType, signedStepSize,
480 builder.getDenseI64ArrayAttr(shape));
482 arith::MulFOp::create(builder, loc, halfConst, signedStepSize);
483 auto halfStepBroadcast =
484 BroadcastOp::create(builder, loc, positionType, halfStep,
485 builder.getDenseI64ArrayAttr(shape));
489 arith::MulFOp::create(builder, loc, halfStepBroadcast, leaf.
grad);
490 Value pHalf = arith::SubFOp::create(builder, loc, leaf.
p, deltaP1);
495 auto deltaQ = arith::MulFOp::create(builder, loc, stepSizeBroadcast, v);
496 Value qNew = arith::AddFOp::create(builder, loc, leaf.
q, deltaQ);
503 arith::MulFOp::create(builder, loc, halfStepBroadcast, gradResult.grad);
504 Value pNew = arith::SubFOp::create(builder, loc, pHalf, deltaP2);
506 return {qNew, pNew, gradResult.grad, gradResult.U, gradResult.rng};
510 Value pRight, Value pSum,
const NUTSContext &ctx) {
515 auto zeroConst = arith::ConstantOp::create(
516 builder, loc, scalarType,
517 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
518 auto halfConst = arith::ConstantOp::create(
519 builder, loc, scalarType,
520 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.5)));
528 auto halfBroadcast = BroadcastOp::create(
529 builder, loc, positionType, halfConst,
530 builder.getDenseI64ArrayAttr(positionType.getShape()));
532 auto pLeftPlusPRight = arith::AddFOp::create(builder, loc, pLeft, pRight);
534 arith::MulFOp::create(builder, loc, halfBroadcast, pLeftPlusPRight);
535 Value pSumCentered = arith::SubFOp::create(builder, loc, pSum, halfSum);
537 auto leftAngle = impulse::DotOp::create(
538 builder, loc, scalarType, vLeft, pSumCentered,
539 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({}),
540 builder.getDenseI64ArrayAttr({0, 1}),
541 builder.getDenseI64ArrayAttr({0, 1}));
542 auto rightAngle = impulse::DotOp::create(
543 builder, loc, scalarType, vRight, pSumCentered,
544 builder.getDenseI64ArrayAttr({}), builder.getDenseI64ArrayAttr({}),
545 builder.getDenseI64ArrayAttr({0, 1}),
546 builder.getDenseI64ArrayAttr({0, 1}));
549 auto leftNeg = arith::CmpFOp::create(builder, loc, arith::CmpFPredicate::OLE,
550 leftAngle, zeroConst);
551 auto rightNeg = arith::CmpFOp::create(builder, loc, arith::CmpFPredicate::OLE,
552 rightAngle, zeroConst);
554 return arith::OrIOp::create(builder, loc, leftNeg, rightNeg);
561 arith::SubFOp::create(builder, loc, newWeight, currentWeight);
562 return impulse::LogisticOp::create(builder, loc, weightDiff.getType(),
567 Value currentWeight, Value newWeight,
568 Value turning, Value diverging) {
569 auto resultType = cast<RankedTensorType>(currentWeight.getType());
570 auto elemType = resultType.getElementType();
572 auto zeroConst = arith::ConstantOp::create(
573 builder, loc, resultType,
574 DenseElementsAttr::get(resultType, builder.getFloatAttr(elemType, 0.0)));
575 auto oneConst = arith::ConstantOp::create(
576 builder, loc, resultType,
577 DenseElementsAttr::get(resultType, builder.getFloatAttr(elemType, 1.0)));
580 arith::SubFOp::create(builder, loc, newWeight, currentWeight);
581 Value expDiff = math::ExpOp::create(builder, loc, weightDiff);
583 arith::MinimumFOp::create(builder, loc, oneConst, expDiff);
584 Value turningOrDiverging =
585 arith::OrIOp::create(builder, loc, turning, diverging);
586 return arith::SelectOp::create(builder, loc, resultType, turningOrDiverging,
587 zeroConst, clippedProb);
593 Value direction, Value rng,
bool biased,
598 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
600 auto zeroConst = arith::ConstantOp::create(
601 builder, loc, scalarType,
602 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
603 auto oneConst = arith::ConstantOp::create(
604 builder, loc, scalarType,
605 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
607 auto qLeft = impulse::SelectOp::create(builder, loc, positionType, direction,
609 auto pLeft = impulse::SelectOp::create(builder, loc, positionType, direction,
611 auto gradLeft = impulse::SelectOp::create(
613 auto qRight = impulse::SelectOp::create(builder, loc, positionType, direction,
615 auto pRight = impulse::SelectOp::create(builder, loc, positionType, direction,
618 impulse::SelectOp::create(builder, loc, positionType, direction,
621 auto combinedWeight = impulse::LogAddExpOp::create(
625 Value transitionProb;
635 auto randomOp = impulse::RandomOp::create(
636 builder, loc, TypeRange{rng.getType(), scalarType}, rng, zeroConst,
638 impulse::RngDistributionAttr::get(builder.getContext(),
639 impulse::RngDistribution::UNIFORM));
640 auto rngOut = randomOp.getOutputRngState();
641 auto uniformSample = randomOp.getResult();
643 auto acceptNew = arith::CmpFOp::create(
644 builder, loc, arith::CmpFPredicate::OLT, uniformSample, transitionProb);
647 impulse::SelectOp::create(builder, loc, positionType, acceptNew,
650 impulse::SelectOp::create(builder, loc, positionType, acceptNew,
652 auto UProposal = impulse::SelectOp::create(
654 auto HProposal = impulse::SelectOp::create(
657 auto oneI64 = arith::ConstantOp::create(
658 builder, loc, i64TensorType,
659 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
660 auto combinedDepth = arith::AddIOp::create(builder, loc, tree.
depth, oneI64);
662 Value combinedTurning;
665 builder, loc, pLeft, pRight,
666 arith::AddFOp::create(builder, loc, tree.
p_sum, subTree.
p_sum), ctx);
668 arith::OrIOp::create(builder, loc, subTree.
turning, turningCheck);
670 combinedTurning = tree.
turning;
673 auto combinedDiverging =
675 auto sumAcceptProbs = arith::AddFOp::create(
677 auto numProposals = arith::AddIOp::create(builder, loc, tree.
num_proposals,
679 auto pSum = arith::AddFOp::create(builder, loc, tree.
p_sum, subTree.
p_sum);
681 return {.q_left = qLeft,
683 .grad_left = gradLeft,
686 .grad_right = gradRight,
687 .q_proposal = qProposal,
688 .grad_proposal = gradProposal,
689 .U_proposal = UProposal,
690 .H_proposal = HProposal,
691 .depth = combinedDepth,
692 .weight = combinedWeight,
693 .turning = combinedTurning,
694 .diverging = combinedDiverging,
695 .sum_accept_probs = sumAcceptProbs,
696 .num_proposals = numProposals,
708 auto initSplit = impulse::RandomSplitOp::create(
709 builder, loc, TypeRange{rng.getType(), rng.getType()}, rng);
710 auto kernelSplit = impulse::RandomSplitOp::create(
711 builder, loc, TypeRange{rng.getType(), rng.getType(), rng.getType()},
712 initSplit.getResult(0));
713 auto rngForSampleKernel = kernelSplit.getResult(0);
714 auto rngForAutodiff = kernelSplit.getResult(1);
720 q0 = initialPosition;
721 auto flatType = RankedTensorType::get({ctx.
positionSize}, elemType);
722 auto q0Flat = impulse::ReshapeOp::create(builder, loc, flatType, q0);
723 SmallVector<Value> callArgs;
724 callArgs.push_back(q0Flat);
726 auto callOp = func::CallOp::create(builder, loc, ctx.
logpdfFn,
727 TypeRange{scalarType}, callArgs);
728 U0 = arith::NegFOp::create(builder, loc, callOp.getResult(0));
734 auto q0_constrained =
744 SmallVector<Value> generateInputsInit;
745 generateInputsInit.push_back(rngForAutodiff);
748 SmallVector<Type> generateResultTypesInit;
749 generateResultTypesInit.push_back(fullTraceType);
750 generateResultTypesInit.push_back(scalarType);
754 auto generateOpInit = impulse::GenerateOp::create(
755 builder, loc, generateResultTypesInit, ctx.
fn, generateInputsInit,
757 builder.getStringAttr(
""));
759 auto weight0 = generateOpInit.getWeight();
760 auto negWeight0 = arith::NegFOp::create(builder, loc, weight0);
763 U0 = arith::SubFOp::create(builder, loc, negWeight0, jacobian0);
768 auto flatType = RankedTensorType::get({ctx.
positionSize}, elemType);
769 Value autodiffQ0 = q0;
770 auto autodiffQ0Type = positionType;
771 auto autodiffGradType = positionType;
772 if (isCustomLogpdf) {
773 autodiffQ0 = impulse::ReshapeOp::create(builder, loc, flatType, q0);
774 autodiffQ0Type = flatType;
775 autodiffGradType = flatType;
778 auto gradSeedInit = arith::ConstantOp::create(
779 builder, loc, scalarType,
780 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
781 SmallVector<Value> autodiffInputs{autodiffQ0, gradSeedInit};
782 SmallVector<NamedAttribute> adInitAttrs{
783 builder.getNamedAttr(
785 builder.getArrayAttr({enzyme::ActivityAttr::get(
786 builder.getContext(), enzyme::Activity::enzyme_active)})),
787 builder.getNamedAttr(
789 builder.getArrayAttr(
790 {enzyme::ActivityAttr::get(builder.getContext(),
791 enzyme::Activity::enzyme_active),
792 enzyme::ActivityAttr::get(builder.getContext(),
793 enzyme::Activity::enzyme_const)})),
797 adInitAttrs.push_back(attr);
799 auto autodiffInit = enzyme::AutoDiffRegionOp::create(
801 TypeRange{scalarType, rngForAutodiff.getType(), autodiffGradType},
802 autodiffInputs, adInitAttrs);
804 Block *autodiffInitBlock = builder.createBlock(&autodiffInit.getBody());
805 autodiffInitBlock->addArgument(autodiffQ0Type, loc);
807 builder.setInsertionPointToStart(autodiffInitBlock);
808 auto q0Arg = autodiffInitBlock->getArgument(0);
810 if (isCustomLogpdf) {
811 SmallVector<Value> callArgs;
812 callArgs.push_back(q0Arg);
814 auto callOpInner = func::CallOp::create(builder, loc, ctx.
logpdfFn,
815 TypeRange{scalarType}, callArgs);
817 arith::NegFOp::create(builder, loc, callOpInner.getResult(0));
818 enzyme::YieldOp::create(builder, loc, {U0_init, rngForAutodiff});
822 auto q0Arg_constrained =
827 SmallVector<Value> generateInputsInner;
828 generateInputsInner.push_back(rngForAutodiff);
831 SmallVector<Type> generateResultTypesInner;
832 generateResultTypesInner.push_back(fullTraceType);
833 generateResultTypesInner.push_back(scalarType);
837 auto generateOpInner = impulse::GenerateOp::create(
838 builder, loc, generateResultTypesInner, ctx.
fn, generateInputsInner,
840 builder.getStringAttr(
""));
843 arith::NegFOp::create(builder, loc, generateOpInner.getWeight());
847 arith::SubFOp::create(builder, loc, negWeightInit, jacobianInit);
849 SmallVector<Value> yieldValues{U0_init, generateOpInner.getResult(2)};
850 enzyme::YieldOp::create(builder, loc, yieldValues);
852 builder.setInsertionPointAfter(autodiffInit);
854 Value grad0 = autodiffInit.getResult(2);
855 if (isCustomLogpdf) {
856 grad0 = impulse::ReshapeOp::create(builder, loc, positionType, grad0);
859 return {q0, U0, grad0, rngForSampleKernel};
863 Value grad, Value U, Value rng,
868 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
869 auto i1TensorType = RankedTensorType::get({}, builder.getI1Type());
876 auto numStepsF64 = math::CeilOp::create(builder, loc, trajDivStep);
878 arith::FPToSIOp::create(builder, loc, i64TensorType, numStepsF64);
879 auto adjustedStepSize =
885 auto sampleKernelSplit = impulse::RandomSplitOp::create(
886 builder, loc, TypeRange{rng.getType(), rng.getType(), rng.getType()},
888 auto rngNext = sampleKernelSplit.getResult(0);
889 auto rngMomentum = sampleKernelSplit.getResult(1);
890 auto rngTransition = sampleKernelSplit.getResult(2);
893 Value rngForMomentum = rngMomentum;
895 auto momSplit = impulse::RandomSplitOp::create(
896 builder, loc, TypeRange{rng.getType(), rng.getType()}, rngMomentum);
897 rngForMomentum = momSplit.getResult(0);
899 auto [p0, rngAfterMomentum] =
907 auto H0 = arith::AddFOp::create(builder, loc, U, K0);
910 auto direction = arith::ConstantOp::create(
911 builder, loc, i1TensorType,
912 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
true)));
914 auto c0 = arith::ConstantOp::create(
915 builder, loc, i64TensorType,
916 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
917 auto c1 = arith::ConstantOp::create(
918 builder, loc, i64TensorType,
919 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
922 SmallVector<Type> loopResultTypes = {positionType, positionType, positionType,
923 scalarType, rngTransition.getType()};
925 impulse::ForOp::create(builder, loc, loopResultTypes, c0, numSteps, c1,
926 ValueRange{q, p0, grad, U, rngTransition});
928 Block *loopBody = builder.createBlock(&forLoopOp.getRegion());
929 loopBody->addArgument(i64TensorType, loc);
930 loopBody->addArgument(positionType, loc);
931 loopBody->addArgument(positionType, loc);
932 loopBody->addArgument(positionType, loc);
933 loopBody->addArgument(scalarType, loc);
934 loopBody->addArgument(rngTransition.getType(), loc);
936 builder.setInsertionPointToStart(loopBody);
937 auto qLoop = loopBody->getArgument(1);
938 auto pLoop = loopBody->getArgument(2);
939 auto gradLoop = loopBody->getArgument(3);
940 auto rngLoop = loopBody->getArgument(5);
947 impulse::YieldOp::create(
948 builder, loc, ValueRange{step.q, step.p, step.grad, step.U, step.rng});
950 builder.setInsertionPointAfter(forLoopOp);
951 auto qProposal = forLoopOp.getResult(0);
952 auto pProposal = forLoopOp.getResult(1);
953 auto gradProposal = forLoopOp.getResult(2);
954 auto UProposal = forLoopOp.getResult(3);
955 auto rngAfterLeapfrog = forLoopOp.getResult(4);
960 auto H1 = arith::AddFOp::create(builder, loc, UProposal, K1);
963 auto zeroConst = arith::ConstantOp::create(
964 builder, loc, scalarType,
965 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
966 auto oneConst = arith::ConstantOp::create(
967 builder, loc, scalarType,
968 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
971 auto dH = arith::SubFOp::create(builder, loc, H0, H1);
972 auto expDH = math::ExpOp::create(builder, loc, dH);
973 auto accProb = arith::MinimumFOp::create(builder, loc, oneConst, expDH);
976 auto randomOp = impulse::RandomOp::create(
977 builder, loc, TypeRange{rngAfterLeapfrog.getType(), scalarType},
978 rngAfterLeapfrog, zeroConst, oneConst,
979 impulse::RngDistributionAttr::get(builder.getContext(),
980 impulse::RngDistribution::UNIFORM));
981 auto randUniform = randomOp.getResult();
984 auto acceptedTensor = arith::CmpFOp::create(
985 builder, loc, arith::CmpFPredicate::OLT, randUniform, accProb);
988 auto falseConst = arith::ConstantOp::create(
989 builder, loc, i1TensorType,
990 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
false)));
993 auto qFinal = impulse::SelectOp::create(builder, loc, positionType,
994 acceptedTensor, qProposal, q);
995 auto gradFinal = impulse::SelectOp::create(
996 builder, loc, positionType, acceptedTensor, gradProposal, grad);
997 auto UFinal = impulse::SelectOp::create(builder, loc, scalarType,
998 acceptedTensor, UProposal, U);
1000 return {qFinal, gradFinal, UFinal, acceptedTensor,
1001 falseConst, accProb, rngNext};
1005 Value grad, Value U, Value rng,
1010 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1011 auto i1TensorType = RankedTensorType::get({}, builder.getI1Type());
1014 auto sampleKernelSplit = impulse::RandomSplitOp::create(
1015 builder, loc, TypeRange{rng.getType(), rng.getType(), rng.getType()},
1017 auto rngNext = sampleKernelSplit.getResult(0);
1018 auto rngMomentum = sampleKernelSplit.getResult(1);
1019 auto rngTree = sampleKernelSplit.getResult(2);
1022 Value rngForMomentum = rngMomentum;
1024 auto momSplit = impulse::RandomSplitOp::create(
1025 builder, loc, TypeRange{rng.getType(), rng.getType()}, rngMomentum);
1026 rngForMomentum = momSplit.getResult(0);
1028 auto [p0, rngAfterMomentum] =
1036 auto H0 = arith::AddFOp::create(builder, loc, U, K0);
1039 auto iterCtx = ctx.
withH0(H0);
1041 auto zeroI64 = arith::ConstantOp::create(
1042 builder, loc, i64TensorType,
1043 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1044 auto falseConst = arith::ConstantOp::create(
1045 builder, loc, i1TensorType,
1046 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
false)));
1047 auto zeroConst = arith::ConstantOp::create(
1048 builder, loc, scalarType,
1049 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
1058 .grad_proposal = grad,
1062 .weight = zeroConst,
1063 .turning = falseConst,
1064 .diverging = falseConst,
1065 .sum_accept_probs = zeroConst,
1066 .num_proposals = zeroI64,
1071 auto finalTree =
buildTree(builder, loc, initialTree, iterCtx, debugDump);
1074 auto trueConst = arith::ConstantOp::create(
1075 builder, loc, i1TensorType,
1076 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
true)));
1079 auto oneI64 = arith::ConstantOp::create(
1080 builder, loc, i64TensorType,
1081 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1082 auto numProposalsClamped =
1083 arith::MaxSIOp::create(builder, loc, finalTree.num_proposals, oneI64);
1084 auto numProposalsFloat =
1085 arith::SIToFPOp::create(builder, loc, scalarType, numProposalsClamped);
1086 auto meanAcceptProb = arith::DivFOp::create(
1087 builder, loc, finalTree.sum_accept_probs, numProposalsFloat);
1089 return {finalTree.q_proposal,
1090 finalTree.grad_proposal,
1091 finalTree.U_proposal,
1093 finalTree.diverging,
1104 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1105 auto i1TensorType = RankedTensorType::get({}, builder.getI1Type());
1107 auto oneConst = arith::ConstantOp::create(
1108 builder, loc, scalarType,
1109 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
1110 auto zeroI64 = arith::ConstantOp::create(
1111 builder, loc, i64TensorType,
1112 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1113 auto oneI64 = arith::ConstantOp::create(
1114 builder, loc, i64TensorType,
1115 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1116 auto falseConst = arith::ConstantOp::create(
1117 builder, loc, i1TensorType,
1118 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
false)));
1125 auto gradNew = leap.
grad;
1127 auto rngOut = leap.
rng;
1131 auto HNew = arith::AddFOp::create(builder, loc, UNew, KNew);
1132 Value deltaH = arith::SubFOp::create(builder, loc, HNew, ctx.
H0);
1135 auto isNan = arith::CmpFOp::create(builder, loc, arith::CmpFPredicate::UNE,
1137 auto infConst = arith::ConstantOp::create(
1138 builder, loc, scalarType,
1139 DenseElementsAttr::get(
1140 scalarType, builder.getFloatAttr(
1141 elemType, std::numeric_limits<double>::infinity())));
1142 deltaH = arith::SelectOp::create(builder, loc, scalarType, isNan, infConst,
1145 auto treeWeight = arith::NegFOp::create(builder, loc, deltaH);
1148 auto diverging = arith::CmpFOp::create(
1149 builder, loc, arith::CmpFPredicate::OGT, deltaH, ctx.
maxDeltaEnergy);
1151 auto negDeltaH = arith::NegFOp::create(builder, loc, deltaH);
1152 auto expNegDelta = math::ExpOp::create(builder, loc, negDeltaH);
1154 arith::MinimumFOp::create(builder, loc, oneConst, expNegDelta);
1156 return {.q_left = qNew,
1158 .grad_left = gradNew,
1161 .grad_right = gradNew,
1163 .grad_proposal = gradNew,
1167 .weight = treeWeight,
1168 .turning = falseConst,
1169 .diverging = diverging,
1170 .sum_accept_probs = acceptProb,
1171 .num_proposals = oneI64,
1182 auto leafQ = impulse::SelectOp::create(builder, loc, positionType, direction,
1184 auto leafP = impulse::SelectOp::create(builder, loc, positionType, direction,
1186 auto leafGrad = impulse::SelectOp::create(
1188 return {leafQ, leafP, leafGrad};
1194 Value direction, Value pCkpts, Value pSumCkpts,
1196 auto i1TensorType = RankedTensorType::get({}, builder.getI1Type());
1197 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1198 auto pCkptsType = cast<RankedTensorType>(pCkpts.getType());
1199 auto trueConst = arith::ConstantOp::create(
1200 builder, loc, i1TensorType,
1201 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
true)));
1202 auto oneI64 = arith::ConstantOp::create(
1203 builder, loc, i64TensorType,
1204 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1205 auto zeroI64 = arith::ConstantOp::create(
1206 builder, loc, i64TensorType,
1207 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1210 auto maxNumProposals =
1211 arith::ShLIOp::create(builder, loc, oneI64, initialTree.
depth);
1213 SmallVector<Type> whileTypes = initialTree.
getTypes();
1214 whileTypes.push_back(pCkptsType);
1215 whileTypes.push_back(pCkptsType);
1216 whileTypes.push_back(i64TensorType);
1218 SmallVector<Value> whileInitVals = initialTree.
toValues();
1219 whileInitVals[15] = zeroI64;
1220 whileInitVals.push_back(pCkpts);
1221 whileInitVals.push_back(pSumCkpts);
1222 whileInitVals.push_back(zeroI64);
1225 impulse::WhileOp::create(builder, loc, whileTypes, whileInitVals);
1228 Block *condBlock = builder.createBlock(&whileOp.getConditionRegion());
1229 for (
auto type : whileTypes)
1230 condBlock->addArgument(type, loc);
1232 builder.setInsertionPointToStart(condBlock);
1233 SmallVector<Value> condTreeArgs(condBlock->getArguments().begin(),
1234 condBlock->getArguments().begin() + 18);
1237 auto numProposalsCheck =
1238 arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::slt,
1241 arith::XOrIOp::create(builder, loc, condTree.
turning, trueConst);
1243 arith::XOrIOp::create(builder, loc, condTree.
diverging, trueConst);
1244 auto continueCond = arith::AndIOp::create(
1246 arith::AndIOp::create(builder, loc, numProposalsCheck, notTurning),
1250 impulse::YieldOp::create(builder, loc, ValueRange{continueCond});
1252 Block *bodyBlock = builder.createBlock(&whileOp.getBodyRegion());
1253 for (
auto type : whileTypes)
1254 bodyBlock->addArgument(type, loc);
1256 builder.setInsertionPointToStart(bodyBlock);
1258 SmallVector<Value> bodyTreeArgs(bodyBlock->getArguments().begin(),
1259 bodyBlock->getArguments().begin() + 18);
1261 auto bodyPCkpts = bodyBlock->getArgument(18);
1262 auto bodyPSumCkpts = bodyBlock->getArgument(19);
1263 auto bodyLeafIdx = bodyBlock->getArgument(20);
1269 auto rngSplit2 = impulse::RandomSplitOp::create(
1270 builder, loc, TypeRange{bodyTree.
rng.getType(), bodyTree.
rng.getType()},
1272 auto rngNext = rngSplit2.getResult(0);
1273 auto rngCombine = rngSplit2.getResult(1);
1280 auto isFirstLeaf = arith::CmpIOp::create(
1281 builder, loc, arith::CmpIPredicate::eq, bodyTree.
num_proposals, zeroI64);
1283 SmallVector<Type> treeTypes = newLeaf.
getTypes();
1284 auto ifOp = impulse::IfOp::create(builder, loc, treeTypes, isFirstLeaf);
1286 Block *trueBranch = builder.createBlock(&ifOp.getTrueBranch());
1287 builder.setInsertionPointToStart(trueBranch);
1288 impulse::YieldOp::create(builder, loc, newLeaf.
toValues());
1291 Block *falseBranch = builder.createBlock(&ifOp.getFalseBranch());
1292 builder.setInsertionPointToStart(falseBranch);
1294 combineTrees(builder, loc, bodyTree, newLeaf, direction, rngCombine,
1296 impulse::YieldOp::create(builder, loc, combinedTree.
toValues());
1299 builder.setInsertionPointAfter(ifOp);
1301 SmallVector<Value>(ifOp.getResults().begin(), ifOp.getResults().end()));
1302 updatedTree.
rng = rngNext;
1305 auto [ckptIdxMin, ckptIdxMax] =
1308 builder, loc, bodyLeafIdx, ckptIdxMax, newLeaf.
p_right, updatedTree.
p_sum,
1309 bodyPCkpts, bodyPSumCkpts, ctx, debugDump);
1311 builder, loc, newLeaf.
p_right, updatedTree.
p_sum, updatedPCkpts,
1312 updatedPSumCkpts, ckptIdxMin, ckptIdxMax, ctx, debugDump);
1315 impulse::SelectOp::create(builder, loc, i1TensorType, isFirstLeaf,
1316 newLeaf.
turning, iterativeTurning);
1318 auto nextLeafIdx = arith::AddIOp::create(builder, loc, bodyLeafIdx, oneI64);
1320 SmallVector<Value> yieldVals = updatedTree.
toValues();
1321 yieldVals.push_back(updatedPCkpts);
1322 yieldVals.push_back(updatedPSumCkpts);
1323 yieldVals.push_back(nextLeafIdx);
1324 impulse::YieldOp::create(builder, loc, yieldVals);
1326 builder.setInsertionPointAfter(whileOp);
1328 SmallVector<Value> resultTreeArgs(whileOp.getResults().begin(),
1329 whileOp.getResults().begin() + 18);
1331 auto resultPCkpts = whileOp.getResult(18);
1332 auto resultPSumCkpts = whileOp.getResult(19);
1338 return {resultTree, resultPCkpts, resultPSumCkpts};
1343 Value direction, Value pCkpts,
1346 auto rngSplit2 = impulse::RandomSplitOp::create(
1347 builder, loc, TypeRange{tree.
rng.getType(), tree.
rng.getType()},
1349 auto rngSubtree = rngSplit2.getResult(0);
1350 auto rngTransition = rngSplit2.getResult(1);
1353 subTreeInit.
rng = rngSubtree;
1355 builder, loc, subTreeInit, direction, pCkpts, pSumCkpts, ctx, debugDump);
1359 combineTrees(builder, loc, tree, subtreeResult.tree, direction,
1360 rngTransition,
true, ctx);
1362 return {combinedTree, subtreeResult.pCkpts, subtreeResult.pSumCkpts};
1369 cast<RankedTensorType>(ctx.
stepSize.getType()).getElementType();
1370 auto F64TensorType = RankedTensorType::get({}, elemType);
1371 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1372 auto i1TensorType = RankedTensorType::get({}, builder.getI1Type());
1374 auto trueConst = arith::ConstantOp::create(
1375 builder, loc, i1TensorType,
1376 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
true)));
1377 auto halfConst = arith::ConstantOp::create(
1378 builder, loc, F64TensorType,
1379 DenseElementsAttr::get(F64TensorType, builder.getF64FloatAttr(0.5)));
1380 auto zeroConst = arith::ConstantOp::create(
1381 builder, loc, F64TensorType,
1382 DenseElementsAttr::get(F64TensorType, builder.getF64FloatAttr(0.0)));
1383 auto oneConst = arith::ConstantOp::create(
1384 builder, loc, F64TensorType,
1385 DenseElementsAttr::get(F64TensorType, builder.getF64FloatAttr(1.0)));
1387 auto maxTreeDepth = arith::ConstantOp::create(
1388 builder, loc, i64TensorType,
1389 DenseElementsAttr::get(i64TensorType,
1392 auto checkpointType =
1395 SmallVector<Type> whileTypes = initialTree.
getTypes();
1396 SmallVector<Value> whileInitVals = initialTree.
toValues();
1399 impulse::WhileOp::create(builder, loc, whileTypes, whileInitVals);
1402 Block *condBlock = builder.createBlock(&whileOp.getConditionRegion());
1403 for (
auto type : whileTypes)
1404 condBlock->addArgument(type, loc);
1406 builder.setInsertionPointToStart(condBlock);
1408 SmallVector<Value> condArgs(condBlock->getArguments().begin(),
1409 condBlock->getArguments().end());
1412 auto depthCheck = arith::CmpIOp::create(
1413 builder, loc, arith::CmpIPredicate::slt, condTree.
depth, maxTreeDepth);
1415 arith::XOrIOp::create(builder, loc, condTree.
turning, trueConst);
1417 arith::XOrIOp::create(builder, loc, condTree.
diverging, trueConst);
1420 auto continueCond = arith::AndIOp::create(
1421 builder, loc, arith::AndIOp::create(builder, loc, depthCheck, notTurning),
1424 impulse::YieldOp::create(builder, loc, ValueRange{continueCond});
1426 Block *bodyBlock = builder.createBlock(&whileOp.getBodyRegion());
1427 for (
auto type : whileTypes)
1428 bodyBlock->addArgument(type, loc);
1430 builder.setInsertionPointToStart(bodyBlock);
1432 SmallVector<Value> bodyArgs(bodyBlock->getArguments().begin(),
1433 bodyBlock->getArguments().end());
1437 auto zeroCkpts = arith::ConstantOp::create(
1438 builder, loc, checkpointType,
1439 DenseElementsAttr::get(checkpointType, builder.getF64FloatAttr(0.0)));
1440 Value bodyPCkpts = zeroCkpts;
1441 Value bodyPSumCkpts = zeroCkpts;
1443 auto rngSplit3 = impulse::RandomSplitOp::create(
1445 TypeRange{bodyTree.
rng.getType(), bodyTree.
rng.getType(),
1446 bodyTree.
rng.getType()},
1448 auto rngNext = rngSplit3.getResult(0);
1449 auto rngDir = rngSplit3.getResult(1);
1450 auto rngDbl = rngSplit3.getResult(2);
1452 auto directionRandom = impulse::RandomOp::create(
1453 builder, loc, TypeRange{rngDir.getType(), F64TensorType}, rngDir,
1454 zeroConst, oneConst,
1455 impulse::RngDistributionAttr::get(builder.getContext(),
1456 impulse::RngDistribution::UNIFORM));
1458 arith::CmpFOp::create(builder, loc, arith::CmpFPredicate::OLT,
1459 directionRandom.getResult(), halfConst);
1463 treeToDouble.
rng = rngDbl;
1464 auto doubleResult =
doubleTree(builder, loc, treeToDouble, direction,
1465 bodyPCkpts, bodyPSumCkpts, ctx, debugDump);
1468 treeToYield.
rng = rngNext;
1469 impulse::YieldOp::create(builder, loc, treeToYield.
toValues());
1471 builder.setInsertionPointAfter(whileOp);
1473 SmallVector<Value> results(whileOp.getResults().begin(),
1474 whileOp.getResults().end());
1481 auto i64TensorType = cast<RankedTensorType>(leafIdx.getType());
1483 auto oneConst = arith::ConstantOp::create(
1484 builder, loc, i64TensorType,
1485 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1488 auto shiftedIdx = arith::ShRUIOp::create(builder, loc, leafIdx, oneConst);
1490 impulse::PopcountOp::create(builder, loc, i64TensorType, shiftedIdx);
1493 auto leafIdxPlusOne = arith::AddIOp::create(builder, loc, leafIdx, oneConst);
1495 auto minusOneConst = arith::ConstantOp::create(
1496 builder, loc, i64TensorType,
1497 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(-1)));
1498 auto notLeafIdx = arith::XOrIOp::create(builder, loc, leafIdx, minusOneConst);
1501 arith::AndIOp::create(builder, loc, notLeafIdx, leafIdxPlusOne);
1502 Value andMinusOne = arith::SubIOp::create(builder, loc, andResult, oneConst);
1504 impulse::PopcountOp::create(builder, loc, i64TensorType, andMinusOne);
1507 Value idxMaxMinusNumSubtrees =
1508 arith::SubIOp::create(builder, loc, idxMax, numSubtrees);
1510 arith::AddIOp::create(builder, loc, idxMaxMinusNumSubtrees, oneConst);
1512 return {idxMin, idxMax};
1516 Value pSum, Value pCkpts, Value pSumCkpts,
1517 Value idxMin, Value idxMax,
1520 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1521 auto i1TensorType = RankedTensorType::get({}, builder.getI1Type());
1523 auto falseConst = arith::ConstantOp::create(
1524 builder, loc, i1TensorType,
1525 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
false)));
1526 auto oneI64 = arith::ConstantOp::create(
1527 builder, loc, i64TensorType,
1528 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1531 SmallVector<Type> whileTypes = {i64TensorType, i1TensorType};
1532 SmallVector<Value> whileInitVals = {idxMax, falseConst};
1535 impulse::WhileOp::create(builder, loc, whileTypes, whileInitVals);
1536 Block *condBlock = builder.createBlock(&whileOp.getConditionRegion());
1537 condBlock->addArgument(i64TensorType, loc);
1538 condBlock->addArgument(i1TensorType, loc);
1539 builder.setInsertionPointToStart(condBlock);
1541 Value iCond = condBlock->getArgument(0);
1542 Value turningCond = condBlock->getArgument(1);
1544 auto iGeMin = arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::sge,
1546 auto trueConst = arith::ConstantOp::create(
1547 builder, loc, i1TensorType,
1548 DenseElementsAttr::get(i1TensorType, builder.getBoolAttr(
true)));
1549 auto notTurning = arith::XOrIOp::create(builder, loc, turningCond, trueConst);
1550 auto continueLoop = arith::AndIOp::create(builder, loc, iGeMin, notTurning);
1552 impulse::YieldOp::create(builder, loc, ValueRange{continueLoop.getResult()});
1554 Block *bodyBlock = builder.createBlock(&whileOp.getBodyRegion());
1555 bodyBlock->addArgument(i64TensorType, loc);
1556 bodyBlock->addArgument(i1TensorType, loc);
1557 builder.setInsertionPointToStart(bodyBlock);
1558 Value iBody = bodyBlock->getArgument(0);
1560 auto zeroI64 = arith::ConstantOp::create(
1561 builder, loc, i64TensorType,
1562 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1563 Value pLeft = impulse::DynamicSliceOp::create(
1564 builder, loc, positionType, pCkpts, ValueRange{iBody, zeroI64},
1566 Value pSumCkptI = impulse::DynamicSliceOp::create(
1567 builder, loc, positionType, pSumCkpts, ValueRange{iBody, zeroI64},
1571 auto pSumMinusCkpt = arith::SubFOp::create(builder, loc, pSum, pSumCkptI);
1572 Value subtreePSum = arith::AddFOp::create(builder, loc, pSumMinusCkpt, pLeft);
1575 Value turningAtCkpt =
checkTurning(builder, loc, pLeft, p, subtreePSum, ctx);
1577 Value iNext = arith::SubIOp::create(builder, loc, iBody, oneI64);
1578 impulse::YieldOp::create(builder, loc, ValueRange{iNext, turningAtCkpt});
1580 builder.setInsertionPointAfter(whileOp);
1581 return whileOp.getResult(1);
1584std::pair<Value, Value>
1586 Value ckptIdxMax, Value p, Value pSum, Value pCkpts,
1589 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1590 auto oneI64 = arith::ConstantOp::create(
1591 builder, loc, i64TensorType,
1592 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1593 auto zeroI64 = arith::ConstantOp::create(
1594 builder, loc, i64TensorType,
1595 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1597 Value leafIdxBit0 = arith::AndIOp::create(builder, loc, leafIdx, oneI64);
1598 Value isEven = arith::CmpIOp::create(builder, loc, arith::CmpIPredicate::eq,
1599 leafIdxBit0, zeroI64);
1601 auto pCkptsType = cast<RankedTensorType>(pCkpts.getType());
1604 SmallVector<Type> ifResultTypes = {pCkptsType, pCkptsType};
1605 auto ifOp = impulse::IfOp::create(builder, loc, ifResultTypes, isEven);
1607 Block *trueBranch = builder.createBlock(&ifOp.getTrueBranch());
1608 builder.setInsertionPointToStart(trueBranch);
1610 auto updatedPCkpts = impulse::DynamicUpdateSliceOp::create(
1611 builder, loc, pCkptsType, pCkpts, p, ValueRange{ckptIdxMax, zeroI64});
1612 auto updatedPSumCkpts = impulse::DynamicUpdateSliceOp::create(
1613 builder, loc, pCkptsType, pSumCkpts, pSum,
1614 ValueRange{ckptIdxMax, zeroI64});
1616 impulse::YieldOp::create(builder, loc,
1617 ValueRange{updatedPCkpts, updatedPSumCkpts});
1620 Block *falseBranch = builder.createBlock(&ifOp.getFalseBranch());
1621 builder.setInsertionPointToStart(falseBranch);
1623 impulse::YieldOp::create(builder, loc, ValueRange{pCkpts, pSumCkpts});
1626 builder.setInsertionPointAfter(ifOp);
1628 Value finalPCkpts = ifOp.getResult(0);
1629 Value finalPSumCkpts = ifOp.getResult(1);
1631 return {finalPCkpts, finalPSumCkpts};
1636 bool logOfProduct) {
1637 auto stepSizeType = cast<RankedTensorType>(stepSize.getType());
1638 auto elemType = stepSizeType.getElementType();
1639 auto scalarType = RankedTensorType::get({}, elemType);
1640 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1646 auto tenConst = arith::ConstantOp::create(
1647 builder, loc, scalarType,
1648 DenseElementsAttr::get(scalarType,
1649 builder.getFloatAttr(elemType, 10.0)));
1650 Value scaled = arith::MulFOp::create(builder, loc, tenConst, stepSize);
1651 proxCenter = math::LogOp::create(builder, loc, scaled);
1653 auto log10Const = arith::ConstantOp::create(
1654 builder, loc, scalarType,
1655 DenseElementsAttr::get(scalarType,
1656 builder.getFloatAttr(elemType, std::log(10.0))));
1657 Value logStepSize = math::LogOp::create(builder, loc, stepSize);
1658 proxCenter = arith::AddFOp::create(builder, loc, log10Const, logStepSize);
1661 auto zeroConst = arith::ConstantOp::create(
1662 builder, loc, scalarType,
1663 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
1664 auto zeroI64 = arith::ConstantOp::create(
1665 builder, loc, i64TensorType,
1666 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1669 .log_step_size = zeroConst,
1670 .log_step_size_avg = zeroConst,
1671 .gradient_avg = zeroConst,
1672 .step_count = zeroI64,
1673 .prox_center = proxCenter,
1687 auto acceptProbType = cast<RankedTensorType>(acceptProb.getType());
1688 auto elemType = acceptProbType.getElementType();
1689 auto scalarType = RankedTensorType::get({}, elemType);
1690 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1693 auto oneI64 = arith::ConstantOp::create(
1694 builder, loc, i64TensorType,
1695 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1696 Value tNew = arith::AddIOp::create(builder, loc, state.
step_count, oneI64);
1697 Value tFloat = arith::SIToFPOp::create(builder, loc, scalarType, tNew);
1700 auto t0Const = arith::ConstantOp::create(
1701 builder, loc, scalarType,
1702 DenseElementsAttr::get(scalarType,
1703 builder.getFloatAttr(elemType, config.
t0)));
1706 auto targetConst = arith::ConstantOp::create(
1707 builder, loc, scalarType,
1708 DenseElementsAttr::get(
1711 Value g = arith::SubFOp::create(builder, loc, targetConst, acceptProb);
1714 Value tPlusT0 = arith::AddFOp::create(builder, loc, tFloat, t0Const);
1717 auto oneConst = arith::ConstantOp::create(
1718 builder, loc, scalarType,
1719 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 1.0)));
1720 Value weight = arith::DivFOp::create(builder, loc, oneConst, tPlusT0);
1723 Value decay = arith::SubFOp::create(builder, loc, oneConst, weight);
1728 arith::MulFOp::create(builder, loc, decay, state.
gradient_avg);
1729 Value gWeighted = arith::MulFOp::create(builder, loc, weight, g);
1730 Value gAvgNew = arith::AddFOp::create(builder, loc, gAvgDecayed, gWeighted);
1733 Value sqrtT = math::SqrtOp::create(builder, loc, tFloat);
1734 auto gammaConst = arith::ConstantOp::create(
1735 builder, loc, scalarType,
1736 DenseElementsAttr::get(scalarType,
1737 builder.getFloatAttr(elemType, config.
gamma)));
1738 Value sqrtTOverGamma = arith::DivFOp::create(builder, loc, sqrtT, gammaConst);
1740 arith::MulFOp::create(builder, loc, sqrtTOverGamma, gAvgNew);
1741 Value logStepSizeNew =
1742 arith::SubFOp::create(builder, loc, state.
prox_center, adjustment);
1745 auto negKappaConst = arith::ConstantOp::create(
1746 builder, loc, scalarType,
1747 DenseElementsAttr::get(scalarType,
1748 builder.getFloatAttr(elemType, -config.
kappa)));
1749 Value weightT = math::PowFOp::create(builder, loc, tFloat, negKappaConst);
1752 Value oneMinusWeightT =
1753 arith::SubFOp::create(builder, loc, oneConst, weightT);
1754 Value avgDecayed = arith::MulFOp::create(builder, loc, oneMinusWeightT,
1756 Value newContribution =
1757 arith::MulFOp::create(builder, loc, weightT, logStepSizeNew);
1758 Value logStepSizeAvgNew =
1759 arith::AddFOp::create(builder, loc, avgDecayed, newContribution);
1762 .log_step_size = logStepSizeNew,
1763 .log_step_size_avg = logStepSizeAvgNew,
1764 .gradient_avg = gAvgNew,
1774 return math::ExpOp::create(builder, loc, logStepSize);
1778 int64_t positionSize,
bool diagonal) {
1779 auto elemType = builder.getF64Type();
1780 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1781 auto meanType = RankedTensorType::get({positionSize}, elemType);
1783 Value mean = arith::ConstantOp::create(
1784 builder, loc, meanType,
1785 DenseElementsAttr::get(meanType, builder.getFloatAttr(elemType, 0.0)));
1791 m2 = arith::ConstantOp::create(
1792 builder, loc, meanType,
1793 DenseElementsAttr::get(meanType, builder.getFloatAttr(elemType, 0.0)));
1795 auto m2Type = RankedTensorType::get({positionSize, positionSize}, elemType);
1796 m2 = arith::ConstantOp::create(
1797 builder, loc, m2Type,
1798 DenseElementsAttr::get(m2Type, builder.getFloatAttr(elemType, 0.0)));
1801 Value n = arith::ConstantOp::create(
1802 builder, loc, i64TensorType,
1803 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(0)));
1805 return {mean, m2, n};
1819 auto sampleType = cast<RankedTensorType>(sample.getType());
1820 auto elemType = sampleType.getElementType();
1821 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1823 auto oneI64 = arith::ConstantOp::create(
1824 builder, loc, i64TensorType,
1825 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1826 Value nNew = arith::AddIOp::create(builder, loc, state.
n, oneI64);
1828 auto scalarType = RankedTensorType::get({}, elemType);
1829 Value nFloat = arith::SIToFPOp::create(builder, loc, scalarType, nNew);
1831 Value nBroadcast = BroadcastOp::create(builder, loc, sampleType, nFloat,
1832 sampleType.getShape());
1834 Value deltaPre = arith::SubFOp::create(builder, loc, sample, state.
mean);
1836 Value deltaPreOverN =
1837 arith::DivFOp::create(builder, loc, deltaPre, nBroadcast);
1839 arith::AddFOp::create(builder, loc, state.
mean, deltaPreOverN);
1841 Value deltaPost = arith::SubFOp::create(builder, loc, sample, meanNew);
1845 Value product = arith::MulFOp::create(builder, loc, deltaPre, deltaPost);
1846 m2New = arith::AddFOp::create(builder, loc, state.
m2, product);
1848 auto m2Type = cast<RankedTensorType>(state.
m2.getType());
1849 Value outerProduct = impulse::DotOp::create(
1850 builder, loc, m2Type, deltaPost, deltaPre,
1851 builder.getDenseI64ArrayAttr({}),
1852 builder.getDenseI64ArrayAttr({}),
1853 builder.getDenseI64ArrayAttr({}),
1854 builder.getDenseI64ArrayAttr({}));
1855 m2New = arith::AddFOp::create(builder, loc, state.
m2, outerProduct);
1858 return {meanNew, m2New, nNew};
1865 auto m2Type = cast<RankedTensorType>(state.
m2.getType());
1866 auto elemType = m2Type.getElementType();
1867 auto scalarType = RankedTensorType::get({}, elemType);
1868 auto i64TensorType = RankedTensorType::get({}, builder.getI64Type());
1870 auto oneI64 = arith::ConstantOp::create(
1871 builder, loc, i64TensorType,
1872 DenseElementsAttr::get(i64TensorType, builder.getI64IntegerAttr(1)));
1873 Value nMinus1 = arith::SubIOp::create(builder, loc, state.
n, oneI64);
1874 Value nMinus1Float =
1875 arith::SIToFPOp::create(builder, loc, scalarType, nMinus1);
1877 Value nMinus1Bcast = BroadcastOp::create(builder, loc, m2Type, nMinus1Float,
1880 Value cov = arith::DivFOp::create(builder, loc, state.
m2, nMinus1Bcast);
1888 Value nFloat = arith::SIToFPOp::create(builder, loc, scalarType, state.
n);
1890 auto fiveConst = arith::ConstantOp::create(
1891 builder, loc, scalarType,
1892 DenseElementsAttr::get(scalarType,
1893 builder.getFloatAttr(elemType, 5.0)));
1894 Value nPlusFive = arith::AddFOp::create(builder, loc, nFloat, fiveConst);
1896 Value scale = arith::DivFOp::create(builder, loc, nFloat, nPlusFive);
1898 BroadcastOp::create(builder, loc, m2Type, scale, m2Type.getShape());
1899 Value scaledCov = arith::MulFOp::create(builder, loc, scaleBcast, cov);
1901 auto shrinkageBaseConst = arith::ConstantOp::create(
1902 builder, loc, scalarType,
1903 DenseElementsAttr::get(scalarType,
1904 builder.getFloatAttr(elemType, 1e-3 * 5.0)));
1906 arith::DivFOp::create(builder, loc, shrinkageBaseConst, nPlusFive);
1909 Value shrinkageBcast = BroadcastOp::create(builder, loc, m2Type,
1910 shrinkage, m2Type.getShape());
1911 cov = arith::AddFOp::create(builder, loc, scaledCov, shrinkageBcast);
1914 Value shrinkageBcast = BroadcastOp::create(builder, loc, m2Type,
1915 shrinkage, m2Type.getShape());
1917 arith::MulFOp::create(builder, loc, shrinkageBcast, identity);
1918 cov = arith::AddFOp::create(builder, loc, scaledCov, shrinkageI);
1930 SmallVector<AdaptWindow> schedule;
1932 if (numSteps < 20) {
1933 schedule.push_back({0, numSteps - 1});
1938 int64_t startBufferSize = 75;
1939 int64_t endBufferSize = 50;
1940 int64_t initWindowSize = 25;
1942 if ((startBufferSize + endBufferSize + initWindowSize) > numSteps) {
1943 startBufferSize =
static_cast<int64_t
>(0.15 * numSteps);
1944 endBufferSize =
static_cast<int64_t
>(0.1 * numSteps);
1945 initWindowSize = numSteps - startBufferSize - endBufferSize;
1949 schedule.push_back({0, startBufferSize - 1});
1951 int64_t endWindowStart = numSteps - endBufferSize;
1952 int64_t nextWindowSize = initWindowSize;
1953 int64_t nextWindowStart = startBufferSize;
1956 while (nextWindowStart < endWindowStart) {
1957 int64_t curWindowStart = nextWindowStart;
1958 int64_t curWindowSize = nextWindowSize;
1960 if (3 * curWindowSize <= endWindowStart - curWindowStart) {
1961 nextWindowSize = 2 * curWindowSize;
1963 curWindowSize = endWindowStart - curWindowStart;
1966 nextWindowStart = curWindowStart + curWindowSize;
1967 schedule.push_back({curWindowStart, nextWindowStart - 1});
1971 schedule.push_back({endWindowStart, numSteps - 1});
1978 ArrayRef<SupportInfo> supports) {
1979 bool hasConstraints =
false;
1980 for (
const auto &info : supports) {
1981 if (info.support && info.support.getKind() != impulse::SupportKind::REAL) {
1982 hasConstraints =
true;
1986 if (!hasConstraints || supports.empty())
1989 auto inputType = cast<RankedTensorType>(constrained.getType());
1990 auto elemType = inputType.getElementType();
1991 int64_t positionSize = inputType.getShape()[1];
1993 auto positionType1D = RankedTensorType::get({positionSize}, elemType);
1994 Value constrained1D =
1995 impulse::ReshapeOp::create(builder, loc, positionType1D, constrained);
1997 SmallVector<Value> slices;
1998 for (
const auto &info : supports) {
1999 auto sliceType = RankedTensorType::get({info.size}, elemType);
2000 auto slice = impulse::SliceOp::create(
2001 builder, loc, sliceType, constrained1D,
2002 builder.getDenseI64ArrayAttr({info.offset}),
2003 builder.getDenseI64ArrayAttr({info.offset + info.size}),
2004 builder.getDenseI64ArrayAttr({1}));
2005 Value unconstrainedSlice;
2006 if (info.support && info.support.getKind() != impulse::SupportKind::REAL) {
2007 unconstrainedSlice =
2010 unconstrainedSlice = slice;
2013 slices.push_back(unconstrainedSlice);
2017 if (slices.size() == 1) {
2018 result1D = slices[0];
2020 auto resultType1D = RankedTensorType::get({positionSize}, elemType);
2021 result1D = arith::ConstantOp::create(
2022 builder, loc, resultType1D,
2023 DenseElementsAttr::get(resultType1D,
2024 builder.getFloatAttr(elemType, 0.0)));
2026 auto i64ScalarType = RankedTensorType::get({}, builder.getI64Type());
2027 auto elemType1DSlice = RankedTensorType::get({1}, elemType);
2028 auto elemType0D = RankedTensorType::get({}, elemType);
2030 for (
size_t i = 0; i < slices.size(); ++i) {
2031 auto sliceType = cast<RankedTensorType>(slices[i].getType());
2032 int64_t sliceSize = sliceType.getShape()[0];
2034 for (int64_t j = 0; j < sliceSize; ++j) {
2035 auto elemIdx = arith::ConstantOp::create(
2036 builder, loc, i64ScalarType,
2037 DenseElementsAttr::get(i64ScalarType,
2038 builder.getI64IntegerAttr(j)));
2039 auto resultIdx = arith::ConstantOp::create(
2040 builder, loc, i64ScalarType,
2041 DenseElementsAttr::get(i64ScalarType,
2042 builder.getI64IntegerAttr(offset + j)));
2044 auto elemSliced = impulse::DynamicSliceOp::create(
2045 builder, loc, elemType1DSlice, slices[i], ValueRange{elemIdx},
2046 builder.getDenseI64ArrayAttr({1}));
2048 impulse::ReshapeOp::create(builder, loc, elemType0D, elemSliced);
2050 auto resultSliced = impulse::ReshapeOp::create(
2051 builder, loc, RankedTensorType::get({1}, elemType), elem);
2052 result1D = impulse::DynamicUpdateSliceOp::create(
2053 builder, loc, resultType1D, result1D, resultSliced,
2054 ValueRange{resultIdx});
2057 offset += sliceSize;
2061 auto resultType2D = RankedTensorType::get({1, positionSize}, elemType);
2062 return impulse::ReshapeOp::create(builder, loc, resultType2D, result1D);
2066 Value unconstrained,
2067 ArrayRef<SupportInfo> supports) {
2068 bool hasConstraints =
false;
2069 for (
const auto &info : supports) {
2070 if (info.support && info.support.getKind() != impulse::SupportKind::REAL) {
2071 hasConstraints =
true;
2075 if (!hasConstraints || supports.empty())
2076 return unconstrained;
2078 auto inputType = cast<RankedTensorType>(unconstrained.getType());
2079 auto elemType = inputType.getElementType();
2080 int64_t positionSize = inputType.getShape()[1];
2082 auto positionType1D = RankedTensorType::get({positionSize}, elemType);
2083 Value unconstrained1D =
2084 impulse::ReshapeOp::create(builder, loc, positionType1D, unconstrained);
2086 SmallVector<Value> slices;
2087 for (
const auto &info : supports) {
2088 auto sliceType = RankedTensorType::get({info.size}, elemType);
2089 auto slice = impulse::SliceOp::create(
2090 builder, loc, sliceType, unconstrained1D,
2091 builder.getDenseI64ArrayAttr({info.offset}),
2092 builder.getDenseI64ArrayAttr({info.offset + info.size}),
2093 builder.getDenseI64ArrayAttr({1}));
2095 Value constrainedSlice;
2096 if (info.support && info.support.getKind() != impulse::SupportKind::REAL) {
2100 constrainedSlice = slice;
2103 slices.push_back(constrainedSlice);
2107 if (slices.size() == 1) {
2108 result1D = slices[0];
2110 auto resultType1D = RankedTensorType::get({positionSize}, elemType);
2111 result1D = arith::ConstantOp::create(
2112 builder, loc, resultType1D,
2113 DenseElementsAttr::get(resultType1D,
2114 builder.getFloatAttr(elemType, 0.0)));
2116 auto i64ScalarType = RankedTensorType::get({}, builder.getI64Type());
2117 auto elemType1DSlice = RankedTensorType::get({1}, elemType);
2118 auto elemType0D = RankedTensorType::get({}, elemType);
2120 for (
size_t i = 0; i < slices.size(); ++i) {
2121 auto sliceType = cast<RankedTensorType>(slices[i].getType());
2122 int64_t sliceSize = sliceType.getShape()[0];
2124 for (int64_t j = 0; j < sliceSize; ++j) {
2125 auto elemIdx = arith::ConstantOp::create(
2126 builder, loc, i64ScalarType,
2127 DenseElementsAttr::get(i64ScalarType,
2128 builder.getI64IntegerAttr(j)));
2129 auto resultIdx = arith::ConstantOp::create(
2130 builder, loc, i64ScalarType,
2131 DenseElementsAttr::get(i64ScalarType,
2132 builder.getI64IntegerAttr(offset + j)));
2134 auto elemSliced = impulse::DynamicSliceOp::create(
2135 builder, loc, elemType1DSlice, slices[i], ValueRange{elemIdx},
2136 builder.getDenseI64ArrayAttr({1}));
2138 impulse::ReshapeOp::create(builder, loc, elemType0D, elemSliced);
2141 impulse::ReshapeOp::create(builder, loc, elemType1DSlice, elem);
2142 result1D = impulse::DynamicUpdateSliceOp::create(
2143 builder, loc, resultType1D, result1D, resultSliced,
2144 ValueRange{resultIdx});
2147 offset += sliceSize;
2151 auto resultType2D = RankedTensorType::get({1, positionSize}, elemType);
2152 return impulse::ReshapeOp::create(builder, loc, resultType2D, result1D);
2156 Value unconstrained,
2157 ArrayRef<SupportInfo> supports) {
2158 auto inputType = cast<RankedTensorType>(unconstrained.getType());
2159 auto elemType = inputType.getElementType();
2160 auto scalarType = RankedTensorType::get({}, elemType);
2162 Value total = arith::ConstantOp::create(
2163 builder, loc, scalarType,
2164 DenseElementsAttr::get(scalarType, builder.getFloatAttr(elemType, 0.0)));
2166 if (supports.empty())
2169 int64_t positionSize = inputType.getShape()[1];
2170 auto positionType1D = RankedTensorType::get({positionSize}, elemType);
2171 Value unconstrained1D =
2172 impulse::ReshapeOp::create(builder, loc, positionType1D, unconstrained);
2174 for (
const auto &info : supports) {
2175 if (!info.support || info.support.getKind() == impulse::SupportKind::REAL)
2178 auto sliceType = RankedTensorType::get({info.size}, elemType);
2179 auto slice = impulse::SliceOp::create(
2180 builder, loc, sliceType, unconstrained1D,
2181 builder.getDenseI64ArrayAttr({info.offset}),
2182 builder.getDenseI64ArrayAttr({info.offset + info.size}),
2183 builder.getDenseI64ArrayAttr({1}));
2187 total = arith::AddFOp::create(builder, loc, total, jacobian);
static Value gatherPositionFromTrace(OpBuilder &builder, Location loc, Value fullTrace, const HMCContext &ctx)
static Value createPermutationMatrix(OpBuilder &builder, Location loc, RankedTensorType matrixType)
Creates a permutation matrix of size n x n.
static Value scatterPositionToTrace(OpBuilder &builder, Location loc, Value position2d, Value fullTrace, const HMCContext &ctx)
static Value createIdentityMatrix(OpBuilder &builder, Location loc, RankedTensorType matrixType)
Creates a 2D identity matrix of the specified type.
static Value reverseRowsAndColumns(OpBuilder &builder, Location loc, Value matrix)
Computes A[::-1, ::-1] using permutation matrix through P @ A @ P.
PointerType * traceType(LLVMContext &C)
Value computeTotalJacobianCorrection(OpBuilder &builder, Location loc, Value unconstrained, ArrayRef< SupportInfo > supports)
Compute total Jacobian correction for the constrain transform over all position vector slices.
Value finalizeWelford(OpBuilder &builder, Location loc, const WelfordState &state, const WelfordConfig &config)
Finalize Welford state to produce sample covariance (returned as inverse mass matrix).
Value checkTurning(OpBuilder &builder, Location loc, Value pLeft, Value pRight, Value pSum, const NUTSContext &ctx)
U-turn termination criterion.
GradientResult computePotentialAndGradient(OpBuilder &builder, Location loc, Value position, Value rng, const HMCContext &ctx)
Computes potential energy U(q) = -log p(q) and its gradient dU/dq
DualAveragingState initDualAveraging(OpBuilder &builder, Location loc, Value stepSize, bool logOfProduct=false)
Initialize dual averaging state from initial step size.
std::pair< Value, Value > leafIdxToCheckpointIdxs(OpBuilder &builder, Location loc, Value leafIdx)
Computes checkpoint indices from leaf index for iterative turning check.
IntegratorState getLeafFromTree(OpBuilder &builder, Location loc, const NUTSTreeState &tree, Value direction, const NUTSContext &ctx)
Extracts an appropriate leaf based on direction.
std::pair< Value, Value > updateCheckpoints(OpBuilder &builder, Location loc, Value leafIdx, Value ckptIdxMax, Value p, Value pSum, Value pCkpts, Value pSumCkpts, const NUTSContext &ctx, bool debugDump=false)
Update checkpoint arrays at even leaf indices.
SubtreeBuildResult buildIterativeSubtree(OpBuilder &builder, Location loc, const NUTSTreeState &initialTree, Value direction, Value pCkpts, Value pSumCkpts, const NUTSContext &ctx, bool debugDump=false)
Builds a subtree iteratively by appending leaves one at a time.
std::pair< Value, Value > sampleMomentum(OpBuilder &builder, Location loc, Value rng, Value invMass, Value massMatrixSqrt, RankedTensorType positionType, bool debugDump=false)
Samples momentum from N(0, M) where M is the mass matrix.
Value computeUniformTransitionProb(OpBuilder &builder, Location loc, Value currentWeight, Value newWeight)
Computes the uniform transition probability for subtree combination.
SmallVector< AdaptWindow > buildAdaptationSchedule(int64_t numSteps)
Build warmup adaptation schedule.
NUTSTreeState buildBaseTree(OpBuilder &builder, Location loc, const IntegratorState &leaf, Value rng, Value direction, const NUTSContext &ctx)
Builds a base tree (leaf node) by taking one leapfrog step.
Value computeKineticEnergy(OpBuilder &builder, Location loc, Value momentum, Value invMass, RankedTensorType positionType)
Computes K = 0.5 * p^T @ M^-1 @ p
NUTSTreeState combineTrees(OpBuilder &builder, Location loc, const NUTSTreeState &tree, const NUTSTreeState &subTree, Value direction, Value rng, bool biased, const NUTSContext &ctx)
Combines a tree with a newly-built subtree during NUTS doubling process.
Value computeBiasedTransitionProb(OpBuilder &builder, Location loc, Value currentWeight, Value newWeight, Value turning, Value diverging)
Computes the biased transition probability for main tree combination.
Value checkIterativeTurning(OpBuilder &builder, Location loc, Value p, Value pSum, Value pCkpts, Value pSumCkpts, Value idxMin, Value idxMax, const NUTSContext &ctx, bool debugDump=false)
Checkpoint-based iterative turning check.
NUTSTreeState buildTree(OpBuilder &builder, Location loc, const NUTSTreeState &initialTree, const NUTSContext &ctx, bool debugDump=false)
Main NUTS tree building loop.
Value conditionalDump(OpBuilder &builder, Location loc, Value value, StringRef label, bool debugDump)
Conditionally dump a value for debugging.
MCMCKernelResult SampleNUTS(OpBuilder &builder, Location loc, Value q, Value grad, Value U, Value rng, const NUTSContext &ctx, bool debugDump=false)
Single NUTS iteration: momentum sampling + tree building.
InitialHMCState InitHMC(OpBuilder &builder, Location loc, Value rng, const HMCContext &ctx, Value initialPosition=Value(), bool debugDump=false)
Initializes HMC/NUTS state from a trace Specifically:
SubtreeBuildResult doubleTree(OpBuilder &builder, Location loc, const NUTSTreeState &tree, Value direction, Value pCkpts, Value pSumCkpts, const NUTSContext &ctx, bool debugDump=false)
Tree doubling by building a subtree of same depth and combining.
IntegrationResult computeIntegrationStep(OpBuilder &builder, Location loc, const IntegratorState &leaf, Value rng, Value direction, const HMCContext &ctx)
Computes a single leapfrog integration step.
DualAveragingState updateDualAveraging(OpBuilder &builder, Location loc, const DualAveragingState &state, Value acceptProb, const DualAveragingConfig &config)
Update dual averaging state with observed acceptance probability.
Value unconstrainPosition(OpBuilder &builder, Location loc, Value constrained, ArrayRef< SupportInfo > supports)
Transform an entire position vector from constrained to unconstrained space based on the support info...
Value computeMassMatrixSqrt(OpBuilder &builder, Location loc, Value invMass, RankedTensorType positionType)
Computes the square root of the mass matrix from the inverse mass matrix.
WelfordState updateWelford(OpBuilder &builder, Location loc, const WelfordState &state, Value sample, const WelfordConfig &config)
Update Welford state with a new sample.
WelfordState initWelford(OpBuilder &builder, Location loc, int64_t positionSize, bool diagonal)
Initialize state for Welford covariance estimation.
Value getStepSizeFromDualAveraging(OpBuilder &builder, Location loc, const DualAveragingState &state, bool final=false)
Get step size from dual averaging state.
MCMCKernelResult SampleHMC(OpBuilder &builder, Location loc, Value q, Value grad, Value U, Value rng, const HMCContext &ctx, bool debugDump=false)
Single HMC iteration: momentum sampling + leapfrog + MH accept/reject.
Value constrainPosition(OpBuilder &builder, Location loc, Value unconstrained, ArrayRef< SupportInfo > supports)
Transform an entire position vector from unconstrained to constrained space.
Value applyInverseMassMatrix(OpBuilder &builder, Location loc, Value invMass, Value momentum, RankedTensorType positionType)
Computes v = M^-1 @ p If invMass is nullptr, returns momentum unchanged (assumes identity) If invMass...
double target_accept_prob
DictionaryAttr autodiffAttrs
Type getElementType() const
HMCContext withStepSize(Value newStepSize) const
ArrayRef< Value > fnInputs
RankedTensorType getPositionType() const
int64_t getFullTraceSize() const
SmallVector< Type > fnResultTypes
SmallVector< SupportInfo > supports
bool hasCustomLogpdf() const
RankedTensorType getScalarType() const
FlatSymbolRefAttr logpdfFn
Result of one MCMC kernel step.
NUTSContext withH0(Value newH0) const
SmallVector< Value > toValues() const
SmallVector< Type > getTypes() const
static NUTSTreeState fromValues(ArrayRef< Value > values)
Configuration for Welford covariance estimation.
State for Welford covariance estimation.