llama-cpp-hs-0.1.0.0: src/Llama/Sampler.hs
{- |
Module : Llama.Sampler
Description : High level Sampler interface for llama-cpp
Copyright : (c) 2025 Tushar Adhatrao
License : MIT
Maintainer : Tushar Adhatrao <tusharadhatrao@gmail.com>
-}
module Llama.Sampler (
defaultSamplerChainParams
, initSampler
, getSamplerName
, acceptTokenWithSampler
, applySampler
, resetSampler
, cloneSampler
, initSamplerChain
, addSamplerToChain
, getSamplerFromChain
, getSamplerChainLength
, removeSamplerFromChain
, initGreedySampler
, initDistributedSampler
, initTopKSampler
, initTopPSampler
, initMinPSampler
, initTypicalSampler
, initTempSampler
, initTempExtSampler
, initXTCSampler
, initTopNSigmaSampler
, initMirostatSampler
, initMirostatV2Sampler
, initGrammarSampler
, initGrammarLazyPatternsSampler
, initPenaltiesSampler
, initDrySampler
, initLogitBiasSampler
, initInfillSampler
, getSamplerSeed
, sampleWithSampler
) where
import Llama.Internal.Types
import Llama.Internal.Types.Params
import Foreign
import Llama.Internal.Foreign
import Foreign.C.String
-- | Convert Storable Haskell struct to pointer and run an action
withStorable :: Storable a => a -> (Ptr a -> IO b) -> IO b
withStorable x f = alloca $ \ptr -> do
poke ptr x
f ptr
-- | Get the default parameters for a sampler chain
defaultSamplerChainParams :: IO LlamaSamplerChainParams
defaultSamplerChainParams = alloca $ \paramsPtr -> do
c_llama_sampler_chain_default_params_into paramsPtr
peek paramsPtr
-- | Initialize a sampler
initSampler :: LlamaSamplerI -> LlamaSamplerContext -> IO (Either String Sampler)
initSampler iface_ ctx_ = do
ifacePtr <- mallocBytes (sizeOf (undefined :: LlamaSamplerI))
poke ifacePtr iface_
samplerPtr <- c_llama_sampler_init ifacePtr ctx_
if samplerPtr == nullPtr
then return $ Left "Failed to initialize sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right (Sampler fp)
-- | Get the name of a sampler
getSamplerName :: Sampler -> IO String
getSamplerName (Sampler samplerFPtr) = do
withForeignPtr samplerFPtr $ \samplerPtr -> do
name_ <- c_llama_sampler_name samplerPtr
peekCString name_
-- | Accept a token with a sampler
acceptTokenWithSampler :: Sampler -> LlamaToken -> IO ()
acceptTokenWithSampler (Sampler samplerFPtr) token_ = do
withForeignPtr samplerFPtr $ \samplerPtr ->
c_llama_sampler_accept samplerPtr token_
-- | Apply a sampler to a token data array
applySampler :: Sampler -> LlamaTokenDataArray -> IO ()
applySampler (Sampler samplerFPtr) tokenDataArray = do
withForeignPtr samplerFPtr $ \samplerPtr ->
withStorable tokenDataArray $ \tokenDataArrayPtr ->
c_llama_sampler_apply samplerPtr tokenDataArrayPtr
-- | Reset a sampler
resetSampler :: Sampler -> IO ()
resetSampler (Sampler samplerFPtr) = do
withForeignPtr samplerFPtr $ \samplerPtr ->
c_llama_sampler_reset (castPtr samplerPtr)
-- | Clone a sampler
cloneSampler :: Sampler -> IO (Either String Sampler)
cloneSampler (Sampler samplerFPtr) = do
withForeignPtr samplerFPtr $ \samplerPtr -> do
clonedSamplerPtr <- c_llama_sampler_clone (castPtr samplerPtr)
if clonedSamplerPtr == nullPtr
then return $ Left "Failed to clone sampler"
else do
fp <- newForeignPtr p_llama_sampler_free clonedSamplerPtr
return $ Right $ Sampler fp
-- | Initialize a sampler chain
initSamplerChain :: LlamaSamplerChainParams -> IO (Either String Sampler)
initSamplerChain params = do
chainPtr <- c_llama_sampler_chain_init params
if chainPtr == nullPtr
then return $ Left "Failed to initialize sampler chain"
else do
fp <- newForeignPtr p_llama_sampler_free chainPtr
return $ Right $ Sampler fp
-- | Add a sampler to a sampler chain
addSamplerToChain :: Sampler -> Ptr LlamaSampler -> IO ()
addSamplerToChain (Sampler chainFPtr) samplerPtr = do
withForeignPtr chainFPtr $ \chainPtr ->
c_llama_sampler_chain_add chainPtr samplerPtr
getSamplerFromChain :: Sampler -> Int -> IO (Either String Sampler)
getSamplerFromChain (Sampler chainFPtr) index = do
withForeignPtr chainFPtr $ \chainPtr -> do
samplerPtr <- c_llama_sampler_chain_get chainPtr (fromIntegral index)
if samplerPtr == nullPtr
then return $ Left "Failed to get sampler from chain"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Get the number of samplers in a sampler chain
getSamplerChainLength :: Sampler -> IO Int
getSamplerChainLength (Sampler chainFPtr) = do
withForeignPtr chainFPtr $ \chainPtr -> do
fromIntegral <$> c_llama_sampler_chain_n chainPtr
-- | Remove a sampler from a sampler chain
removeSamplerFromChain :: Sampler -> Int -> IO (Either String Sampler)
removeSamplerFromChain (Sampler chainFPtr) index = do
withForeignPtr chainFPtr $ \chainPtr -> do
samplerPtr <- c_llama_sampler_chain_remove chainPtr (fromIntegral index)
if samplerPtr == nullPtr
then return $ Left "Failed to remove sampler from chain"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a greedy sampler
initGreedySampler :: IO (Either String (Ptr LlamaSampler))
initGreedySampler = do
samplerPtr <- c_llama_sampler_init_greedy
if samplerPtr == nullPtr
then return $ Left "Failed to initialize greedy sampler"
else do
return $ Right samplerPtr
-- | Initialize a distributed sampler
initDistributedSampler :: Word32 -> IO (Either String Sampler)
initDistributedSampler seed = do
samplerPtr <- c_llama_sampler_init_dist (fromIntegral seed)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize distributed sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a top-k sampler
initTopKSampler :: Int -> IO (Either String Sampler)
initTopKSampler k = do
samplerPtr <- c_llama_sampler_init_top_k (fromIntegral k)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize top-k sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a top-p sampler
initTopPSampler :: Float -> Int -> IO (Either String Sampler)
initTopPSampler p1 minKeep = do
samplerPtr <- c_llama_sampler_init_top_p (realToFrac p1) (fromIntegral minKeep)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize top-p sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a min-p sampler
initMinPSampler :: Float -> Int -> IO (Either String Sampler)
initMinPSampler p1 minKeep = do
samplerPtr <- c_llama_sampler_init_min_p (realToFrac p1) (fromIntegral minKeep)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize min-p sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a typical sampler
initTypicalSampler :: Float -> Int -> IO (Either String Sampler)
initTypicalSampler p_ minKeep = do
samplerPtr <- c_llama_sampler_init_typical (realToFrac p_) (fromIntegral minKeep)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize typical sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a temperature sampler
initTempSampler :: Float -> IO (Either String Sampler)
initTempSampler t = do
samplerPtr <- c_llama_sampler_init_temp (realToFrac t)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize temperature sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize an extended temperature sampler
initTempExtSampler :: Float -> Float -> Float -> IO (Either String Sampler)
initTempExtSampler t delta exponent_ = do
samplerPtr <- c_llama_sampler_init_temp_ext (realToFrac t) (realToFrac delta) (realToFrac exponent_)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize extended temperature sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize an XTC sampler
initXTCSampler :: Float -> Float -> Int -> Word32 -> IO (Either String Sampler)
initXTCSampler p1 t minKeep seed = do
samplerPtr <- c_llama_sampler_init_xtc (realToFrac p1) (realToFrac t) (fromIntegral minKeep) (fromIntegral seed)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize XTC sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a top-N sigma sampler
initTopNSigmaSampler :: Float -> IO (Either String Sampler)
initTopNSigmaSampler n = do
samplerPtr <- c_llama_sampler_init_top_n_sigma (realToFrac n)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize top-N sigma sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a Mirostat sampler
initMirostatSampler :: Int -> Word32 -> Float -> Float -> Int -> IO (Either String Sampler)
initMirostatSampler nVocab seed tau eta m = do
samplerPtr <- c_llama_sampler_init_mirostat (fromIntegral nVocab) (fromIntegral seed) (realToFrac tau) (realToFrac eta) (fromIntegral m)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize Mirostat sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a Mirostat V2 sampler
initMirostatV2Sampler :: Word32 -> Float -> Float -> IO (Either String Sampler)
initMirostatV2Sampler seed tau eta = do
samplerPtr <- c_llama_sampler_init_mirostat_v2 (fromIntegral seed) (realToFrac tau) (realToFrac eta)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize Mirostat V2 sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a grammar sampler
initGrammarSampler :: Vocab -> String -> String -> IO (Either String Sampler)
initGrammarSampler (Vocab vocab) grammarStr grammarRoot = do
withForeignPtr vocab $ \vocabPtr -> do
withCString grammarStr $ \grammarStrPtr -> do
withCString grammarRoot $ \grammarRootPtr -> do
samplerPtr <- c_llama_sampler_init_grammar (CLlamaVocab vocabPtr) grammarStrPtr grammarRootPtr
if samplerPtr == nullPtr
then return $ Left "Failed to initialize grammar sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a grammar sampler with lazy patterns
initGrammarLazyPatternsSampler :: Vocab -> String -> String -> [String] -> [LlamaToken] -> IO (Either String Sampler)
initGrammarLazyPatternsSampler (Vocab vocab) grammarStr grammarRoot triggerPatterns triggerTokens = do
withForeignPtr vocab $ \vocabPtr -> do
withCString grammarStr $ \grammarStrPtr -> do
withCString grammarRoot $ \grammarRootPtr -> do
triggerPatternsPtr <- newArrayOfPtrs triggerPatterns
withForeignPtr triggerPatternsPtr $ \triggerPatternsPtr' -> do
triggerTokensPtr <- mallocBytes (length triggerTokens * sizeOf (undefined :: LlamaToken))
pokeArray triggerTokensPtr triggerTokens
samplerPtr <- c_llama_sampler_init_grammar_lazy_patterns
(CLlamaVocab vocabPtr)
grammarStrPtr
grammarRootPtr
triggerPatternsPtr'
(fromIntegral (length triggerPatterns))
triggerTokensPtr
(fromIntegral (length triggerTokens))
if samplerPtr == nullPtr
then return $ Left "Failed to initialize grammar lazy patterns sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a penalties sampler
initPenaltiesSampler :: Int -> Float -> Float -> Float -> IO (Either String Sampler)
initPenaltiesSampler penaltyLastN penaltyRepeat penaltyFreq penaltyPresent = do
samplerPtr <- c_llama_sampler_init_penalties
(fromIntegral penaltyLastN)
(realToFrac penaltyRepeat)
(realToFrac penaltyFreq)
(realToFrac penaltyPresent)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize penalties sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
newArrayOfPtrs :: [String] -> IO (ForeignPtr CString)
newArrayOfPtrs xs = do
ptrs <- mallocBytes (length xs * sizeOf (undefined :: Ptr CString))
mapM_ (\(i, x) -> withCString x $ \cstr -> poke (castPtr ptrs `plusPtr` (i * sizeOf (undefined :: Ptr CString))) cstr) (zip [0..] xs)
newForeignPtr_ ptrs
-- Helper function
withCStringArray :: [String] -> (Ptr CString -> IO a) -> IO a
withCStringArray xs f = do
ptrs <- newArrayOfPtrs xs
withForeignPtr ptrs $ \ptrs' ->
f ptrs'
-- | Initialize a dry sampler
initDrySampler :: Vocab -> Int -> Float -> Float -> Int -> Int -> [String] -> IO (Either String Sampler)
initDrySampler (Vocab vocab) nCtxTrain dryMultiplier dryBase dryAllowedLength dryPenaltyLastN seqBreakers = do
withForeignPtr vocab $ \vocabPtr -> do
withCStringArray seqBreakers $ \seqBreakersPtr -> do
samplerPtr <- c_llama_sampler_init_dry
(CLlamaVocab vocabPtr)
(fromIntegral nCtxTrain)
(realToFrac dryMultiplier)
(realToFrac dryBase)
(fromIntegral dryAllowedLength)
(fromIntegral dryPenaltyLastN)
seqBreakersPtr
(fromIntegral (length seqBreakers))
if samplerPtr == nullPtr
then return $ Left "Failed to initialize dry sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize a logit bias sampler
initLogitBiasSampler :: Int -> [LlamaLogitBias] -> IO (Either String Sampler)
initLogitBiasSampler nVocab logitBiases = do
allocaArray (length logitBiases) $ \logitBiasPtr -> do
pokeArray logitBiasPtr logitBiases
samplerPtr <- c_llama_sampler_init_logit_bias
(fromIntegral nVocab)
(fromIntegral (length logitBiases))
logitBiasPtr
if samplerPtr == nullPtr
then return $ Left "Failed to initialize logit bias sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Initialize an infill sampler
initInfillSampler :: Vocab -> IO (Either String Sampler)
initInfillSampler (Vocab vocab) = do
withForeignPtr vocab $ \vocabPtr -> do
samplerPtr <- c_llama_sampler_init_infill (CLlamaVocab vocabPtr)
if samplerPtr == nullPtr
then return $ Left "Failed to initialize infill sampler"
else do
fp <- newForeignPtr p_llama_sampler_free samplerPtr
return $ Right $ Sampler fp
-- | Get the seed used by a sampler
getSamplerSeed :: Sampler -> IO Word32
getSamplerSeed (Sampler samplerFPtr) = do
withForeignPtr samplerFPtr (fmap fromIntegral . c_llama_sampler_get_seed)
-- | Sample with a sampler
sampleWithSampler :: Sampler -> Context -> Int -> IO LlamaToken
sampleWithSampler (Sampler samplerFPtr) (Context ctxFPtr) idx = do
withForeignPtr samplerFPtr $ \samplerPtr -> do
withForeignPtr ctxFPtr $ \ctxPtr ->
c_llama_sampler_sample samplerPtr (CLlamaContext ctxPtr) (fromIntegral idx)