Diffusion/Common/Utils.swift (61 lines of code) (raw):
//
// Utils.swift
// Diffusion
//
// Created by Pedro Cuenca on 14/1/23.
// See LICENSE at https://github.com/huggingface/swift-coreml-diffusers/LICENSE
//
import Foundation
extension String: Error {}
extension Double {
func formatted(_ format: String) -> String {
return String(format: "\(format)", self)
}
}
extension String {
var first200Safe: String {
let endIndex = index(startIndex, offsetBy: Swift.min(200, count))
let substring = String(self[startIndex..<endIndex])
// Replace whitespace with underscore or dash
let replacedSubstring = substring
.replacingOccurrences(of: " ", with: "_")
.replacingOccurrences(of: "\t", with: "_")
.replacingOccurrences(of: "\n", with: "_")
// Remove unsafe characters from the substring
let allowedCharacters = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "-_"))
let filteredSubstring = replacedSubstring
.components(separatedBy: allowedCharacters.inverted)
.joined()
return filteredSubstring
}
}
/// Returns an array of booleans that indicates at which steps a preview should be generated.
///
/// - Parameters:
/// - numInferenceSteps: The total number of inference steps.
/// - numPreviews: The desired number of previews.
///
/// - Returns: An array of booleans of size `numInferenceSteps`, where `true` values represent steps at which a preview should be made.
func previewIndices(_ numInferenceSteps: Int, _ numPreviews: Int) -> [Bool] {
// Ensure valid parameters
guard numInferenceSteps > 0, numPreviews > 0 else {
return [Bool](repeating: false, count: numInferenceSteps)
}
// Compute the ideal (floating-point) step size, which represents the average number of steps between previews
let idealStep = Double(numInferenceSteps) / Double(numPreviews)
// Compute the actual steps at which previews should be made. For each preview, we multiply the ideal step size by the preview number, and round to the nearest integer.
// The result is converted to a `Set` for fast membership tests.
let previewIndices: Set<Int> = Set((0..<numPreviews).map { previewIndex in
return Int(round(Double(previewIndex) * idealStep))
})
// Construct an array of booleans where each value indicates whether or not a preview should be made at that step.
let previewArray = (0..<numInferenceSteps).map { previewIndices.contains($0) }
return previewArray
}
extension Double {
func reduceScale(to places: Int) -> Double {
let multiplier = pow(10, Double(places))
let newDecimal = multiplier * self // move the decimal right
let truncated = Double(Int(newDecimal)) // drop the fraction
let originalDecimal = truncated / multiplier // move the decimal back
return originalDecimal
}
}
func formatLargeNumber(_ n: UInt32) -> String {
let num = abs(Double(n))
switch num {
case 1_000_000_000...:
var formatted = num / 1_000_000_000
formatted = formatted.reduceScale(to: 3)
return "\(formatted)B"
case 1_000_000...:
var formatted = num / 1_000_000
formatted = formatted.reduceScale(to: 3)
return "\(formatted)M"
case 1_000...:
return "\(n)"
case 0...:
return "\(n)"
default:
return "\(n)"
}
}