function random_walk!(g::DAG, n::Int64)
    # the purpose here is to do "random" operations on the graph to simulate an optimizer
    reset_graph!(g)

    properties = get_properties(g)

    for i in 1:n
        # choose push or pop
        if rand(Bool)
            # push
            opt = get_operations(g)

            # choose one of fuse/split/reduce
            option = rand(1:3)
            if option == 1 && !isempty(opt.nodeFusions)
                push_operation!(g, rand(collect(opt.nodeFusions)))
            elseif option == 2 && !isempty(opt.nodeReductions)
                push_operation!(g, rand(collect(opt.nodeReductions)))
            elseif option == 3 && !isempty(opt.nodeSplits)
                push_operation!(g, rand(collect(opt.nodeSplits)))
            else
                i = i - 1
            end
        else
            # pop
            if (can_pop(g))
                pop_operation!(g)
            else
                i = i - 1
            end
        end
    end

    return nothing
end

function reduce_all!(g::DAG)
    reset_graph!(g)

    opt = get_operations(g)
    while (!isempty(opt.nodeReductions))
        push_operation!(g, pop!(opt.nodeReductions))

        if (isempty(opt.nodeReductions))
            opt = get_operations(g)
        end
    end
    return nothing
end

function reduce_one!(g::DAG)
    opt = get_operations(g)
    if !isempty(opt.nodeReductions)
        push_operation!(g, pop!(opt.nodeReductions))
    end
    opt = get_operations(g)
    return nothing
end